[專題研究分享] 基於機器學習的心臟衰竭患者存活率預測與關鍵臨床特徵分析


編輯製作
:莊紹甫、蔡豐聲

出品團隊:中國醫藥大學 醫療資訊學系 程式俱樂部

YThttps://youtu.be/AGBd4j27txE

📌 參考文獻與資料來源 (References & Datasets)

  • 論文參考:Davide Chicco, Giuseppe Jurman: "Machine learning can predict survival of patients with heart failure from serum creatinine and ejection fraction alone". BMC Medical Informatics and Decision Making 20, 16 (2020). DOI 連結

  • Kaggle 資料集Heart Failure Clinical Records Dataset (by Nima Pourmoradi)

  • 技術參考:Zeyad Sayed: "Predicting Heart Failure Fatality using XGBoost" (2024)

💡 專題簡介 (Introduction)

心臟衰竭是全球常見且死亡率高昂的慢性疾病。本專題旨在透過 Kaggle 的心臟衰竭臨床數據,利用 Python 進行完整數據預處理、特徵工程,並結合 Optuna 自動超參數搜尋XGBoost 機器學習模型,建構心臟衰竭患者死亡/存活風險的預測模型。最後,引入 SHAP 可解釋性分析,協助醫療人員理解影響存活率的關鍵臨床指標。

📊 臨床數據集說明 (Dataset Overview)

資料集包含了患者的各項生理數據與臨床指標(如年齡、血清肌酸酐、射血分數、血小板量、高血壓及吸菸狀態等):

ageanaemiacreatinine_phosphokinasediabetesejection_fractionhigh_blood_pressureplateletsserum_creatinineserum_sodiumDEATH_EVENT
75.005820201265,0001.91301
55.007,8610380263,3581.11361
65.001460200162,0001.31291
50.011110200210,0001.91371

🛠️ 完整作業流程與 Prompt 指令明細

Step 1. 數據讀取 (Data Loading)

  • 📌 詳細步驟說明:從 Google Drive 指定路徑中載入心臟衰竭數據集 CSV 檔案

  • 💬 Prompt 指令

    幫我讀取 /content/drive/MyDrive/心臟衰竭/heart_failure_clinical_records_dataset.csv 檔案

Step 2. EDA 分析 (Exploratory Data Analysis)

  • 📌 詳細步驟說明:對載入的數據進行探索性資料分析,並將分析結果與相關圖表繪製出來

  • 💬 Prompt 指令

    幫我對這份檔案做 EDA 分析,並顯示出來。

Step 3. 訓練數據與標籤分離 (Label Extraction & Split)

  • 📌 詳細步驟說明:處理數據框 df,針對目標欄位 DEATH_EVENT 使用 pop() 方法抽出作為目標標籤變數 $y$,其餘特徵變數則留存為新變數 $x$

  • 💬 Prompt 指令

    幫我處理 df 的 dataframe 的目標欄位 DEATH_EVENT,將這個欄位使用 pop 來抽出來存成新的變數 y,剩餘特徵存成新變數 x。

Step 4. 特徵工程 (Feature Engineering)

  • 📌 詳細步驟說明:針對特徵數據框 $x$ 進行以下三階段處置

    1. 極值修剪 (Capping):針對 ejection_fraction 欄位,若數值大於 60 則強制修改為 60,將結果存成新欄位 ef_capped

    2. 對數轉換 (Log Transform):對 creatinine_phosphokinaseserum_creatinineplatelets 這三個欄位進行對數轉換,保留原始欄位並將結果分別存成帶有 _log 結尾的新欄位(例如:platelets_log

    3. 複合特徵計算與新增

      • 新增 heart_kidney_score:計算公式為 $\text{ejection\_fraction} / \text{serum\_creatinine}$

      • 新增 comorbidity_score:計算公式為將 anaemiadiabeteshigh_blood_pressuresmoking 四個欄位的值沿著橫列 (axis=1) 直接相加

      • 新增 frailty_index:計算公式為 $\text{age} / \text{ejection\_fraction}$

      • 新增 renal_sodium_risk:計算公式為 $(\text{serum\_creatinine} / \text{serum\_sodium}) \times 100$

  • 💬 Prompt 指令

    我有一個名為 x 的 DataFrame 針對 ejection_fraction 這個欄位進行 capping。具體規則:如果數值大於 60,則強制修改為 60。請將結果存成一個新欄位叫做 ef_capped。只要執行這個動作就好。

    延續剛剛的 x。請幫我針對 creatinine_phosphokinase、serum_creatinine、以及 platelets 這三個欄位,進行對數轉換。請將轉換後的結果分別存成帶有 _log 結尾的新欄位(例如:platelets_log)。請注意:請保留原始欄位,並且只要處理這三個指定的欄位就好。

    針對名為 x 的 DataFrame。幫我新增 4 個複合特徵欄位:新增 heart_kidney_score:計算公式為 ejection_fraction / serum_creatinine。新增 comorbidity_score:計算公式為將 anaemia, diabetes, high_blood_pressure, smoking 這四個欄位的值沿著橫列 (axis=1) 直接相加。新增 frailty_index:計算公式為 age / ejection_fraction。新增 renal_sodium_risk:計算公式為 (serum_creatinine / serum_sodium) * 100。並顯示出來。

Step 5. 切分訓練集跟驗證集 (Data Splitting)

  • 📌 詳細步驟說明:將處理完的 $x$ 資料框切分為 80% 的訓練集與 20% 的測試集

  • 💬 Prompt 指令

    接下來幫我對 x 的 dataframe 做切分 80% 的訓練集跟 20% 的測試集

Step 6. 模型訓練 (Optuna + XGBoost + Early Stopping)

  • 📌 詳細步驟說明與語法限制

    1. 使用 !pip install optuna 安裝套件。計算 y_train 的比例以計算 scale_pos_weight 處理不平衡資料,並使用 StratifiedKFold 交叉驗證與 Optuna 套件以 AUC 為目標進行自動超參數搜尋

    2. 參數設定限制:在 Optuna 設定超參數字典 (params) 時,絕對不可early_stopping_roundseval_metricverbosity 寫進字典中,這三個參數必須且只能獨立寫在 xgb.XGBClassifier() 括號內。同時亦不可加入 use_label_encoder 參數

    3. 模型訓練與監控:呼叫 model.fit() 時在訓練過程中監控 logloss 以防範過擬合 (Early Stopping)model.fit() 括號內只能包含 X_train, y_train, eval_set=[(X_train, y_train), (X_test, y_test)] 以及 verbose=False絕對不可出現 callbacksearly_stopping_roundseval_metricevals_result

    4. 學習曲線繪製:訓練完成踩完煞車後,直接提取 final_model.evals_result_ 內建屬性成績單,繪製 Train 與 Test 的 logloss 折線圖

  • 💬 Prompt 指令

    先使用 !pip install optuna 下載套件。計算 y_train 的比例,算 scale_pos_weight,去使用 optuna 套件來做自動調參數。使用 StratifiedKFold 進行交叉驗證,並以 AUC 為優化目標。

    接著,呼叫 xgboost 模型,並套用剛剛使用 optuna 套件找到的超參數。以下語法限制適用於 Optuna 的 objective 函數內部,以及最終模型的建立。在 Optuna 設定超參數字典 (params) 時,絕對不可以把 early_stopping_rounds、eval_metric 或 verbosity 寫進字典裡,這三個參數必須、且只能獨立寫在 xgb.XGBClassifier 的括號中。不能加入 use_label_encoder 參數。接下來進入訓練階段,請呼叫 model.fit()。透過前面的設定,讓模型在訓練的同時監控 logloss 的變化,以防止 overfitting,並在真正 overfitting 前自動踩煞車停止訓練。model.fit() 括號裡面只能放 X_train, y_train、eval_set=[(X_train, y_train), (X_test, y_test)] 以及 verbose=False, 絕對不可以出現 callbacks、early_stopping_rounds、eval_metric 或 evals_result。等到模型訓練完全結束並踩完煞車後,請直接使用 eval_results = final_model.evals_result_ 這個內建屬性來提取成績單,以供後續畫圖使用。

    最後,請直接提取模型內建的 evals_result_ 屬性來取得成績,並把這個結果畫 Train 與 Test 的 logloss 折線圖顯示出來。

Step 7. 模型評估 (Model Evaluation)

  • 📌 詳細步驟說明:針對訓練完畢的模型進行性能指標評估,包含輸出完整分類報表、繪製混淆矩陣 (Confusion Matrix) 以及 AUC-ROC 曲線圖

  • 💬 Prompt 指令

    我的模型已經訓練完畢 接下來要對訓練好的模型來看評估指標,印出包含 Accuracy、Precision、Recall、F1-score 的完整報表,並繪製混淆矩陣。

    幫我依據我的訓練結果印出 AUC-ROC 的完整報表與繪製圖片。

Step 8. 模型解釋 (Model Interpretation)

  • 📌 詳細步驟說明:引入 SHAP (SHapley Additive exPlanations) 套件,繪製特徵重要性長條圖,分析模型決策時看重的關鍵臨床特徵

  • 💬 Prompt 指令

    幫我引入 SHAP 解釋模型看重那些特徵並繪製長條圖表顯示出來。

程式俱樂部YT頻道 https://www.youtube.com/@tsai-cai