☰
基于Python与机器学习的急性心肌梗死死亡风险预测:XGBoost与LightGBM实战
2026/10/3 2:47:19 网站建设 项目流程

简介:本资源为基于Python与机器学习的急性心肌梗死死亡风险预测项目,面向计算机、人工智能及医学信息相关专业的毕业设计、课程设计与项目开发学习者,提供一套可运行的完整预测方案。项目以MIMIC数据库数据为训练集,围绕死亡率预测任务展开,涵盖数据预处理、特征工程与多种机器学习模型训练流程,适合作为入门级医疗数据挖掘实战参考。压缩包共14个文件,约5.7MB,包含4个Python脚本、3个CSV数据文件、2个SQL查询脚本,以及xlsx、txt、md说明文档和开源协议等,覆盖数据提取、模型训练与结果记录等环节。目前已有236人学习下载。读者可获取完整源码与配套文档,理解从SQL取数到模型评估的完整链路,并在此基础上替换数据集或调整模型进行延伸开发,同时也能通过文档快速了解项目结构与运行方式。

1. 从一份 AMI 死亡风险预测源码包说起:它到底能跑出什么

急性心肌梗死(AMI)患者的死亡风险预测,是医学机器学习里被反复做的题目。我手上这份资源包叫「基于python+机器学习的急性心肌梗死死亡风险预测」,压缩包解压后是AMI_morality_prediction-master目录,里面躺着xgb.py、TrainLightGBM.py、PreProecssOneHot.py、PreProcessInsert.py,外加GET_AMI.sql、GET_WBC.sql两个取数脚本和一份 README。它干的事很明确:拿 MIMIC 数据库里的重症监护记录当训练集,用 XGBoost 和 LightGBM 两个梯度提升树模型,预测心梗患者住院期间的死亡结局,作者声称准确率能到 95% 以上。

如果你是做毕业设计或课程设计的学生,这份包的价值在于流程完整——从 SQL 取数、独热编码预处理,到两个树模型训练脚本,一条链路都给你铺好了,改改路径就能跑。但我要先把话说在前面:这个 95% 的准确率有很强的场景依赖,MIMIC 里心梗相关的指标多是血压、心率这类离散记录,而真正进 ICU 的病人身上挂着监护仪,医生看心电图判读的准确率本来就轻松过 95%。所以这份资源适合拿来学「医学表格数据的完整建模流程」,不适合当成能上临床的预测系统。想清楚这一点,后面每一步你都不会走偏。

2. 数据从哪来、怎么进模型:MIMIC 取数与独热编码链路

2.1 两个 SQL 脚本的分工

包里的GET_AMI.sql和GET_WBC.sql是整个流程的源头。前者负责从 MIMIC 的icustays、patients、admissions等表里捞出心梗相关的诊断与生命体征记录,后者专门取白细胞(WBC)等实验室指标。MIMIC 的数据组织方式是「事件表 + 字典表」,d_items存指标定义,chartevents存每次测量值,所以取数时基本都要 join 一次字典表把itemid翻译成人能看懂的名字。

-- GET_AMI.sql 的核心思路(示意,字段名以你本地 MIMIC 版本为准) SELECT ie.subject_id, ie.hadm_id, ie.icustay_id, ie.intime, ie.outtime, ce.charttime, ce.itemid, ce.valuenum, di.label -- 指标名称,如 Heart Rate、Arterial BP FROM icustays ie LEFT JOIN chartevents ce ON ie.icustay_id = ce.icustay_id LEFT JOIN d_items di ON ce.itemid = di.itemid WHERE di.label IN ('Heart Rate', 'Arterial Blood Pressure systolic', ...) ORDER BY ie.subject_id, ce.charttime;

逻辑说明:icustays是 ICU 停留主表,一次住院可能对应多段 ICU 记录,用icustay_id关联chartevents才能拿到时间序列。valuenum是数值型测量结果,文本型结果在value字段里,做数值建模时只取valuenum。参数上要注意charttime是测量时刻,后面做特征聚合(比如取每天均值、最大值)全靠它。

提示:MIMIC 各版本表结构有差异,MIMIC-III 用icustay_id,MIMIC-IV 改成了stay_id,直接套脚本大概率报字段不存在,先对着你本地库的 schema 核一遍。

2.2 独热编码为什么放在预处理里

PreProecssOneHot.py(文件名拼写有误,不影响运行)干的是把类别型特征转成独热向量。心梗数据里性别、入院类型、部分诊断编码都是类别变量,树模型虽然对类别不敏感,但独热后特征空间更规整,也方便后面统一做缺失值填充。常见做法是用 pandas 的get_dummies,或者 sklearn 的OneHotEncoder。

import pandas as pd def one_hot_encode(df, cat_cols): # cat_cols 是类别列名列表,比如 ['gender', 'admission_type'] df = pd.get_dummies(df, columns=cat_cols, dummy_na=False) return df if __name__ == "__main__": raw = pd.read_csv("ami_raw.csv") cat_cols = ["gender", "admission_type", "insurance"] encoded = one_hot_encode(raw, cat_cols) encoded.to_csv("ami_encoded.csv", index=False)

逻辑说明:get_dummies会为每个类别值生成一列 0/1 特征,dummy_na=False表示缺失值不单独成一列,避免特征维度爆炸。参数上columns必须传实际存在的列名,传错会直接抛 KeyError。PreProcessInsert.py则是把处理好的特征写回数据库或落盘,两个脚本一读一写,构成预处理闭环。

2.3 特征聚合的隐藏工作量

原始chartevents是逐次测量记录,一个病人一天可能有几十条心率,直接喂给模型维度对不齐。所以预处理阶段通常要按subject_id + 时间窗做聚合,取均值、最大值、最小值、标准差。这一步脚本里未必写全,但你不做,模型输入就是乱的。我一般会先按天分组,再对每个指标算统计量,最后和结局标签(是否死亡)拼成一张宽表。

3. XGBoost 与 LightGBM 双模型:训练脚本怎么读、参数怎么调

3.1 xgb.py 的结构拆解

xgb.py是 XGBoost 训练入口。XGBoost 用二阶泰勒展开加正则项,对中小规模表格数据很稳,医学预测里出镜率极高。脚本大致分四段:读特征表、切训练测试集、定义参数、训练并评估。

import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, roc_auc_score # 1. 读入预处理后的特征表 data = pd.read_csv("ami_encoded.csv") X = data.drop(columns=["label"]) # label 为死亡结局 0/1 y = data["label"] # 2. 切分,stratify 保证正负样本比例一致 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 3. 参数:树深、学习率、评估指标 params = { "max_depth": 4, "learning_rate": 0.05, "n_estimators": 300, "objective": "binary:logistic", "eval_metric": "auc", "subsample": 0.8, "colsample_bytree": 0.8, } model = xgb.XGBClassifier(**params) model.fit(X_train, y_train) pred = model.predict(X_test) print("Accuracy:", accuracy_score(y_test, pred)) print("AUC:", roc_auc_score(y_test, model.predict_proba(X_test)[:, 1]))

逻辑说明:stratify=y是关键,死亡样本通常远少于存活样本,不分层切分会导致测试集里正样本太少,指标虚高。max_depth控制树复杂度,医学数据特征不多时 3~5 就够,调大容易过拟合。learning_rate配n_estimators是一对,学习率小就要更多树。subsample和colsample_bytree是行、列采样比例,起正则作用。

3.2 TrainLightGBM.py 的差异点

LightGBM 用直方图算法和 leaf-wise 生长,训练更快、内存更省,代价是 leaf-wise 在小数据上更容易过拟合。TrainLightGBM.py的骨架和 XGBoost 几乎一样,差别在参数命名和几个专属项。

import lightgbm as lgb params = { "num_leaves": 31, # leaf-wise 的核心参数,控制叶子数 "learning_rate": 0.05, "n_estimators": 300, "objective": "binary", "metric": "auc", "min_child_samples": 20, # 叶子最小样本数,防过拟合 "feature_fraction": 0.8, } model = lgb.LGBMClassifier(**params) model.fit(X_train, y_train)

逻辑说明:num_leaves是 LightGBM 最该盯的参数,它和max_depth不是一回事,叶子数直接决定模型容量,数据量小就往下压。min_child_samples限制每个叶子至少多少样本,样本少时调大能明显抑制过拟合。feature_fraction对应 XGBoost 的colsample_bytree。

3.3 两个模型怎么对比、怎么选

维度XGBoostLightGBM
生长方式level-wiseleaf-wise
训练速度中等快
小数据表现较稳易过拟合,需调 num_leaves
内存占用较高较低
关键防过拟合参数max_depth、subsamplenum_leaves、min_child_samples

实操建议:数据量在几千条以内,优先信 XGBoost 的结果;上万条再让 LightGBM 发挥速度优势。两个都跑一遍,看 AUC 而不是只看准确率——类别不平衡时准确率会骗人。

注意:脚本里如果没做类别不平衡处理,死亡样本占比低时模型会倾向全预测为「存活」,准确率照样能到 90% 以上,但 AUC 会很难看。先看混淆矩阵再信准确率。

4. 环境搭建与复现:从零把这份包跑起来

4.1 依赖安装与版本对齐

这份包依赖 pandas、numpy、scikit-learn、xgboost、lightgbm,可能还有数据库连接库。版本不齐是新手翻车重灾区,尤其是 xgboost 和 sklearn 的接口在不同大版本间改过。

# 建议用虚拟环境隔离,避免污染全局 python -m venv ami_env source ami_env/bin/activate # Windows 用 ami_env\Scripts\activate pip install pandas numpy scikit-learn xgboost lightgbm # 如果脚本连数据库,再补一个 pip install sqlalchemy psycopg2-binary

逻辑说明:虚拟环境能锁住依赖版本,换机器复现时不容易崩。psycopg2-binary是 PostgreSQL 驱动,MIMIC 通常部署在 PostgreSQL 上,取数脚本要用它。装完先pip freeze > requirements.txt存一份,方便别人复现。

4.2 数据准备的两条路

第一条路是本地已有 MIMIC 数据库,直接改 SQL 脚本里的连接串和表名,跑PreProcessInsert.py生成特征表。第二条路是拿不到数据库,那就得自己造一份结构相同的 CSV,字段对齐后跳过 SQL 环节,直接从PreProecssOneHot.py开始跑。第二条路适合只想学建模流程的人,但结论不能当真实医学结论用。

4.3 跑通顺序与验证点

正确顺序是:GET_AMI.sql/GET_WBC.sql取数 →PreProcessInsert.py落库或落盘 →PreProecssOneHot.py编码 →xgb.py/TrainLightGBM.py训练。每步跑完都该有个可检查的产物:取数后看行数和字段数,编码后看特征维度有没有异常膨胀,训练后看 AUC 和混淆矩阵。哪一步产物对不上,就停在那一步查,别硬往下跑。

5. 避坑与常见问题排查:那些让指标虚高的细节

5.1 准确率 95% 但 AUC 只有 0.6

现象:脚本打印 Accuracy 0.95,但 roc_auc_score 只有 0.6 左右。原因:死亡样本占比极低,模型全预测为存活也能拿高准确率,这是类别不平衡下的经典假象。解决:改用 AUC、F1、召回率评估,训练时加scale_pos_weight(XGBoost)或class_weight='balanced',必要时上 SMOTE 过采样。

5.2 独热后特征维度爆炸

现象:编码后特征从几十列涨到几千列,训练极慢甚至内存溢出。原因:某些高基数类别列(如诊断编码)被get_dummies展开成海量列。解决:对高基数类别改用目标编码或频次编码,或者先做类别合并,把低频类别归到「其他」。

5.3 时间信息泄漏

现象:离线指标漂亮,换个数据集就崩。原因:特征聚合时把结局发生之后才产生的测量值也算进去了,模型提前「看到」了答案。解决:严格按intime到结局时间点切窗,只用预测时点之前的数据构造特征,这一步是医学预测最容易翻车的地方。

5.4 SQL 字段名对不上

现象:跑GET_AMI.sql报 column does not exist。原因:MIMIC-III 和 MIMIC-IV 表结构不同,icustay_id与stay_id、chartevents字段都有差异。解决:先\d chartevents看表结构,按本地版本改字段名,别照抄。

5.5 随机种子没固定导致结果飘

现象:每次跑指标都不一样,没法对比模型。原因:train_test_split和模型初始化没设random_state。解决:切分和模型都固定random_state=42,对比实验才公平。

6. 把这份包用出价值:特征工程与结果验证的进阶手法

跑通只是起点,真正决定这份资源对你有没有用的,是你能不能在上面做出自己的东西。我一般会先做特征重要性分析,XGBoost 和 LightGBM 都能直接输出feature_importances_,把排名前二十的特征拉出来看,如果全是某个单一指标在撑,说明模型没学到东西,得回去补特征。

import pandas as pd import matplotlib.pyplot as plt # 以 XGBoost 为例,model 为已训练模型 importance = pd.Series(model.feature_importances_, index=X_train.columns) importance = importance.sort_values(ascending=False).head(20) importance.plot(kind="barh", figsize=(8, 6)) plt.gca().invert_yaxis() plt.title("Top 20 Feature Importance") plt.tight_layout() plt.savefig("feature_importance.png")

逻辑说明:feature_importances_在树模型里默认按增益或分裂次数统计,不同库口径不同,横向对比时注意统一。head(20)只取前二十,避免图太挤。这张图能帮你判断模型是不是靠合理特征在做预测。

验证环节我强烈建议加交叉验证,单次切分的指标波动太大。用StratifiedKFold做五折,看 AUC 的均值和方差,方差大说明模型不稳。另外可以画校准曲线(calibration curve),医学风险预测里概率是否可信比分类对不对更重要——预测「死亡概率 0.8」和实际 80% 死亡率对得上,模型才有临床讨论价值。

还有个容易被忽略的点:这份包的 README 和文档值得逐行读一遍,作者在预处理里做的取舍(比如哪些指标被丢弃、缺失值怎么填)往往没写进代码注释,但恰恰是复现时最容易卡住的地方。我吃过亏,有次直接跳过文档跑脚本,结果缺失值填充策略和作者不一致,指标差了十几个点,回头翻文档才发现人家用的是中位数填充而不是均值。从那以后我每次拿到别人的包,都强制先把 README 和预处理脚本对着读一遍再动手。希望这份拆解能帮到你,把这份资源真正跑成自己的东西。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询