ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

心衰预测不靠深度学习:LASSO回归+逻辑回归的小样本建模方案

心衰预测不靠深度学习:LASSO回归+逻辑回归的小样本建模方案 简介围绕心脏衰竭致死因素这一医学课题资源提供一套完整的机器学习建模方案适用于数据挖掘学习者与医疗健康领域分析人员。内容以12项临床指标为切入点依次完成可视化探索、统计学相关性检验、Lasso特征筛选并基于逻辑回归、支持向量机与随机森林构建分类预测模型整体思路由浅入深便于理解特征工程与模型对比的完整流程。压缩包共10个文件包含Python与R脚本、原始CSV数据集、项目报告PDF以及README说明可据此直接复现实验并核对关键步骤包体仅240KB轻量紧凑。目前已有803人学习浏览适合想要借鉴医疗预测分析完整代码与写作框架的读者。1. 心衰预测分析不靠堆模型LASSO回归逻辑回归组合才是小样本首选把299条心衰患者记录丢给深度学习大概率得到一份漂亮的过拟合曲线换成LASSO回归先筛特征、逻辑回归再分类反而能拿到稳健且能写进报告的AUC。这是机器学习在小样本医疗预测里最常被误用的一类场景数据量不够支撑复杂模型临床解释需求却不低。LASSO回归用L1正则让无关特征系数直接归零逻辑回归在稀疏特征集上给出有概率意义的决策边界两者衔接构成一套完整的心衰预测分析流程。这条链路不需要GPU、不依赖大型预训练模型适合医工交叉科研、毕业设计以及第一次独立完成机器学习全流程的从业者。从数据清洗到报告撰写下面按可复现的顺序拆开讲。2. 心衰数据集预处理13个字段里哪些能直接进LASSO回归模型模型再漂亮填不进脏数据也是白搭。心衰预测分析最常用的公开数据源是UCI的Heart Failure Clinical Records包含299条患者记录、13个字段其中12个为特征、1个为标签。样本量不大训练集和测试集一旦切得不合理后续所有评估都会被污染。这一章先把字段语义理清再处理缺失值、标准化和划分方式保证进入LASSO回归的数据是干净的。2.1 UCI心衰数据集与字段语义2.1.1 字段表与标签定义标签是DEATH_EVENT0表示随访期内存活1表示死亡事件。心衰预测分析里最常见的目标就是预测“这个患者随访期会不会死亡”属于二分类问题。字段含义如下表字段含义类型age年龄数值anaemia是否贫血二分类creatinine_phosphokinase肌酸磷酸激酶数值diabetes是否糖尿病二分类ejection_fraction射血分数%数值high_blood_pressure是否高血压二分类platelets血小板数值serum_creatinine血清肌酐数值serum_sodium血清钠数值sex性别二分类smoking是否吸烟二分类time随访期天数数值DEATH_EVENT死亡事件标签标签注意区分二分类特征和数值特征二分类特征本质是布尔量做标准化没有意义数值特征量纲差异非常大血小板动辄几十万血清钠只有130上下不处理会直接影响后续LASSO回归的惩罚力度。2.1.2 用pandas完成缺失值与重复值检查import pandas as pd import numpy as np df pd.read_csv(heart_failure.csv) print(数据集形状:, df.shape) print(缺失值数量:\n, df.isnull().sum()) print(重复行数量:, df.duplicated().sum()) # 标签分布 print(死亡事件分布:\n, df[DEATH_EVENT].value_counts())这段代码负责三件事确认数据集行列数、检查缺失值分布、检查重复样本。运行后若发现缺失值常见做法是用中位数填充数值列分类列用众数若重复行存在直接去重。299条样本的信息非常宝贵删除记录是最后手段优先考虑填充。2.2 标准化与训练集测试集划分2.2.1 数值型与二分类特征的处理差异from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 二分类特征直接保留0/1不参与标准化 binary_cols [anaemia, diabetes, high_blood_pressure, sex, smoking] num_cols [age, creatinine_phosphokinase, ejection_fraction, platelets, serum_creatinine, serum_sodium, time] X df.drop(DEATH_EVENT, axis1) y df[DEATH_EVENT] # 只对数值特征做标准化 scaler StandardScaler() X_num_scaled scaler.fit_transform(X[num_cols]) X_binary X[binary_cols].values X_processed np.hstack([X_num_scaled, X_binary]) feature_names num_cols binary_cols标准化对LASSO回归是必要条件L1惩罚项对所有特征系数一视同仁量纲大的特征即使真正相关也会因为数值范围大而被错误地保留或淘汰。二分类特征保持0/1即可不参与标准化因为它们的取值本身已经处于同一量纲空间。2.2.2 stratify分层抽样避免类别失真X_train, X_test, y_train, y_test train_test_split( X_processed, y, test_size0.2, stratifyy, random_state42 ) print(训练集样本数:, len(y_train)) print(测试集样本数:, len(y_test)) print(训练集死亡比例: %.3f % y_train.mean()) print(测试集死亡比例: %.3f % y_test.mean())stratifyy是非常关键的一个参数它让划分后的训练集和测试集保持与原始数据相同的类别比例。心衰数据集中死亡事件大约占32%如果随机划分小概率事件会被低估导致训练出来的逻辑回归模型对死亡样本的召回率失真。同时布好random_state42保证后续复现。我用42做初始随机种子实际项目里换成任意固定整数都能锁定划分结果。3. LASSO回归特征筛选交叉验证定λ系数归零才算淘汰进入特征选择阶段。12个特征里真正对心衰死亡有独立贡献的可能只有一半把全部特征直接塞进逻辑回归不仅解释困难还会放大共线性问题。LASSO回归通过L1正则化把不相关特征的系数压缩到0留下来的就是模型认为值得保留的变量。3.1 L1正则如何让无关特征系数收缩为0LASSO回归的目标函数是残差平方和加上L1惩罚项minimize ||y - Xβ||² λ ∑|β_j|λ越大惩罚力度越强系数的绝对值被压缩得越小最终某些系数精确地变成0。这个性质源于L1范数的几何形状约束区域是菱形在顶点处与等误差线相交时必然有坐标轴上的解对应系数为0。这与岭回归的L2范式不同L2只能压缩系数逼近0但不会等于0。所以LASSO回归本身就是特征选择器不需要额外写特征重要性排序代码。3.2 LassoCV自动搜索最优λ3.2.1 核心代码from sklearn.linear_model import LassoCV from sklearn.preprocessing import StandardScaler # X_train 已经是标准化后的数据 lasso LassoCV( cv5, random_state42, max_iter100000, n_alphas200, alphasNone ).fit(X_train, y_train) print(最优alpha(λ):, lasso.alpha_) # 查看每个特征的系数 coef_series pd.Series(lasso.coef_, indexfeature_names) print(非零系数特征:\n, coef_series[coef_series ! 0])3.2.2 参数解读cv、n_alphas、max_itercv5表示采用5折交叉验证选择λ比手动试多个alpha值可靠得多。n_alphas200让模型在200个候选λ上搜索最优值覆盖从大惩罚到小惩罚的完整区间如果数据量更小把这个值降到100也能跑。max_iter100000是迭代次数上限L1优化在特征量纲跨度大时可能不收敛设置足够大的迭代上限能避免警告。alphasNone表示让sklearn根据数据自动生成候选λ序列这是最稳妥的做法手工指定alpha序列很容易漏掉最优区间。3.3 非零系数特征清单与共线性讨论在随机种子固定为42时LASSO回归通常会保留ejection_fraction、serum_creatinine、serum_sodium、age等几个强相关变量。系数会呈现类似下面的形态特征LASSO系数说明ejection_fraction负值且绝对值最大射血分数越低死亡风险越高serum_creatinine正值肌酐反映肾功能越高风险越高serum_sodium负值低钠血症是心衰不良预后标志age正值年龄越大风险越高其余特征0独立贡献不足被淘汰选择保留的标准只有一个系数严格不为0。被淘汰的特征不代表与死亡事件无关而是说明它们的信息已经被保留特征覆盖加入模型只会增加冗余。这一步做完可以把X_train和X_test都按选中的列重新切出来准备进入逻辑回归。4. 逻辑回归建模与评估从系数训练到AUC完整代码特征筛完进入最后的分类环节。逻辑回归算法在医疗预测里的地位一直很稳它能给每个样本输出死亡概率而不是粗暴的类别标签系数取指数后就是OR值比值比临床医生能直接读懂。这一章给出完整的训练、调阈值、评估和OR值解释代码。4.1 用筛选后特征重构逻辑回归模型4.1.1 为什么二次建模用L2惩罚而不是L1第一次用LASSO回归做筛选时已经完成了L1惩罚的“稀疏化”任务二次建模时逻辑回归如果再上L1会让系数继续收缩解释性变差。常见做法是换成L2惩罚岭惩罚让保留特征的系数分布更平滑保留每个变量的独立贡献。整体来看这套组合等价于“先用L1做变量选择再用L2做参数估计”也是小样本回归里的经典两阶段方案。from sklearn.linear_model import LogisticRegression # 按LASSO选出的非零系数列切片 selected_cols coef_series[coef_series ! 0].index.tolist() train_sel pd.DataFrame(X_train, columnsfeature_names)[selected_cols] test_sel pd.DataFrame(X_test, columnsfeature_names)[selected_cols] lr LogisticRegression( penaltyl2, C1.0, solverliblinear, max_iter1000, random_state42 ) lr.fit(train_sel, y_train) # 输出测试集预测概率与类别 y_prob lr.predict_proba(test_sel)[:, 1] y_pred_default (y_prob 0.5).astype(int)C是正则强度的倒数C越小惩罚越强C1.0是sklearn默认值在小样本上通常表现均衡。solver选liblinear而不是lbfgs原因是liblinear对二分类小样本的坐标下降优化更稳定lbfgs在特征量少时也可能出现收敛警告。max_iter设到1000是因为逻辑回归迭代次数不够时最典型的现象是训练集AUC极高但测试集一塌糊涂实际排查时先看有没有ConvergenceWarning。4.2 概率阈值与混淆矩阵的平衡默认0.5的预测阈值并不适合心衰数据。死亡事件占比约32%如果机械地按0.5切分模型会把大量概率在0.4到0.5之间的真实死亡样本判成存活召回率偏低。把阈值下调到0.4能让模型更“敏感”代价是误报增加这个取舍在医疗场景下通常值得。threshold 0.4 y_pred (y_prob threshold).astype(int) tn, fp, fn, tp confusion_matrix(y_test, y_pred).ravel() print(阈值:, threshold) print(混淆矩阵 - TP: %d, FP: %d, FN: %d, TN: %d % (tp, fp, fn, tn)) print(召回率(敏感度): %.3f % (tp / (tp fn))) print(精确率: %.3f % (tp / (tp fp)))混淆矩阵拆成TP、FP、FN、TN四个量之后召回率的含义就很直观所有真实死亡的患者里模型抓住了多大比例。心衰预测分析的目标不是抓越少越稳而是尽量不要漏掉高风险患者所以召回率比精确率优先。4.3 评估指标与OR值临床解释from sklearn.metrics import classification_report, roc_auc_score, roc_curve print(classification_report(y_test, y_pred, target_names[存活, 死亡])) print(AUC: %.3f % roc_auc_score(y_test, y_prob))分类报告通常会长成这样类别precisionrecallf1-scoresupport存活0.800.900.8541死亡0.790.610.6918测试集共59条样本死亡样本18条模型抓住了其中11条同时放过了7条高风险患者。AUC在0.82到0.88之间是这类模型的正常水平低于0.75说明特征选择或预处理出了问题高于0.95就要怀疑是否发生了数据泄漏。逻辑回归最大的优势还在解释。把系数还原为OR值看每个特征的临床意义odds_ratio pd.Series(np.exp(lr.coef_[0]), indexselected_cols).sort_values(ascendingFalse) print(odds_ratio)OR值大于1表示该特征增加死亡风险小于1表示降低。比如serum_creatinine的OR值如果算出3.0临床解读就是“在其他因素不变的情况下血清肌酐每升高一个标准差死亡风险变为原来的3倍”这种结论可以直接写进报告正文。5. 心衰预测报告怎么写特征系数、OR值与三个高频复现坑模型不是终点报告才是交付物。代码和报告一体的心衰预测分析项目报告结构按“数据描述—特征选择—模型评估—临床解释—局限”组织即可。数据描述给出样本量和纳入特征特征选择部分展示LASSO系数表模型评估放混淆矩阵、AUC和ROC曲线临床解释列出每个保留特征的OR值局限部分写明样本量只有299条结论不能外推到其他人群。5.1 报告结构从数据描述到临床结论报告里最容易被忽略的章节是方法描述。单独一段说明“用LASSO回归做特征选择、逻辑回归建模测试集按0.2比例预留并用stratify分层抽样”这比代码本身更重要。临床读者不会看你跑了多少行代码只会关心变量是怎么选出来的、预测结果有多可信。5.2 坑1不标准化直接跑LASSO直接把原始量纲数据丢进LassoCVplatelets背后的惩罚权重会淹没serum_serum_sodium这种取值小但临床意义强的变量。结果就是筛出的特征全是“数值大的”模型AUC还过得去但换一组数据立刻失效。标准化永远在LASSO之前。5.3 坑2只看准确率不看AUC和召回率心衰数据里存活样本占68%全预测存活也有68%准确率。只看准确率会误判模型价值。报告里必须同时给出AUC、召回率、精确率。进一步验证泛化能力时做一个Bootstrap区间from sklearn.metrics import roc_auc_score rng np.random.default_rng(42) aucs [] for _ in range(1000): idx rng.integers(0, len(y_test), len(y_test)) aucs.append(roc_auc_score(y_test.iloc[idx], y_prob[idx])) print(AUC 95%% CI: %.3f - %.3f % (np.percentile(aucs, 2.5), np.percentile(aucs, 97.5)))如果95%置信区间宽度超过0.15说明测试集样本太少结论要写得更谨慎。5.4 坑3阈值0.5对不平衡数据不友好固定阈值0.5需要在精确率和召回率之间二选一。跑完评估后回看混淆矩阵如果FN明显高于FP就把阈值从0.5往0.3方向逐步试观察召回率曲线和AUC变化。选阈值的标准是临床场景宁可多召回几个假阳性患者待复查也不漏掉真实高风险患者。跑通这个项目后把random_state从42换成其他数值重跑一遍AUC变化超过0.05就说明特征选择不稳定回到第3章检查标准化和λ搜索区间。本文还有配套的精品资源点击获取
返回列表