简介:这是一份聚焦结直肠癌早筛的学术文献PDF,目标读者是医学信息、生物医学工程和肿瘤学方向的研究者,尤其在特征筛选与早期诊断建模方面具有直接参考价值。文章系统展示机器学习在血清标志物筛选及早期诊断模型评估中的应用:采用向前法逐步逻辑回归,从CEA、CA1724、CA242、CA153、HSP60中筛选有诊断价值的标志物,并比较LR、SVM与BP神经网络建模效果。结果表明,LR联合检测灵敏度更高,诊断价值优于单一指标和SVM模型,能为理解特征选择、分类建模和诊断效能评价提供直观参考。资源包内含1个PDF,大小449KB,是《解放军预防医学杂志》2016年发表的论文原文,含摘要、关键词、实验数据与参考文献,便于阅读引用。已有309人学习,适合需要快速获取结直肠癌机器学习诊断方案参考的读者。
1. 从18种血清标志物里筛出5个:这篇论文的筛选逻辑值得直接抄作业
处理肿瘤标志物数据的人基本都遇到过同一个尴尬:单项指标特异性不够,十几个指标全塞进模型又过拟合。这篇《基于机器学习的结直肠癌血清标志物筛选及早期诊断模型评估》恰好给了一套标准答案式的流程——用向前法逐步逻辑回归从18种血清标志物中筛出CEA、CA724、CA242、CA153和HSP60共5个,再用LR、SVM、BP三种模型做早期诊断对比。最终LR联合模型AUC达到0.957,SVM准确率85%,BP只有62.5%。如果你是做医学数据分析的,这份PDF能当模板用:特征筛选逻辑、数据编码方式、模型评估口径都有现成的参照。新手照着搭一遍能理解小样本分类建模的完整链路,熟手可以对照检查自己的项目在特征选择和模型比较上有没有踩同样的坑。
2. 向前法逐步逻辑回归:特征筛选的执行流程与方程解读
2.1 为什么选LR做特征筛选而不是直接上树模型
论文没有一上来就把18个指标扔给SVM或BP,而是先用LR的向前法做特征筛选。这个先后顺序在医学诊断场景里是刻意为之的。逻辑回归每个入选变量都带偏回归系数、P值和OR值,可以直接回答“这个标志物是否具有独立诊断价值”;相比之下,随机森林的特征重要性或XGBoost的gain值虽然也能排序,但缺乏严格的统计检验框架,临床审稿人并不买账。另一个现实原因是样本量——160例数据、18个候选特征,特征维度不算低,如果直接丢给BP神经网络,隐含层一多立刻过拟合,而LR的参数量只有18个,在这么小的样本上反而更稳。所以在小样本高维特征的场景里,先做一轮线性筛选再进复杂模型,是比“端到端”更稳妥的路径。
2.2 二值化编码:把检测值变成0/1输入
论文把肿瘤标志物检测水平在正常范围的赋值为0,高于或低于临界值的赋值为1,用二值化后的0/1作为协变量进入LR。二值化的实际好处是绕开不同标志物浓度量纲差异的问题——CEA的参考范围和CA153的参考范围差了好几个数量级,直接拿原始浓度进模型,量纲大的指标会天然主导梯度更新。二值化之后,每个特征都变成“这个指标是否异常”,语义一致,模型系数也能直接解释为异常状态对诊断概率的贡献。这里有一个容易翻车的点:UGT1A8是反向指标,检测值低于临界值时为阳性,高于临界值时反而是阴性。如果跟其他17个标志物统一按“高于临界=1”编码,这个特征的诊断信号就完全反了。我在实际项目里见过不止一次反向指标被当成普通指标处理的情况,编码前一定先看试剂盒说明书里的阳性判定方向。
2.3 向前法逐步回归的执行流程与停止条件
向前法逐步回归的逻辑是:从空模型出发,每次引入一个让似然比检验最显著的变量,引入后立即检查已在模型里的变量有没有因为新变量的加入而变得不显著,如果有就剔除,反复迭代直到没有任何变量能再进入或移出。具体到这篇论文,就是18个指标作为协变量,结直肠癌病理诊断结果作为应变量(癌症=1,良性=0),逐步运算后删掉了13个自变量,最终有5个进入方程。停止条件在不同软件里略有差异:SPSS的“向前:条件”用的是条件参数似然比检验,R的step函数用的是AIC,statsmodels里可以自己写循环。虽然准则不同,但在这个数据量下筛选结果通常只差一两个特征。如果你复现时发现选出的特征组合和论文不完全一致,先别急,用你筛出的组合和论文的组合各跑一遍模型,对比AUC再判断差异是否真的存在。
2.4 LR方程解读与入选指标的临床含义
论文给出的最终LR方程为:
Logit P = -6.025 + 0.105×CEA + 0.154×CA724 + 0.053×CA242 + 0.102×CA153 + 0.004×HSP60
这里有几个值得注意的细节。第一,CA724的系数0.154在五个变量里最大,说明在二值化输入下它对Logit的贡献最显著,这和文献里CA724在消化道肿瘤中诊断价值较高是互相印证的。第二,HSP60的系数只有0.004,虽然P值小于0.05有统计学意义,但贡献非常微弱,这种变量在实际建模里往往是最先被剪枝掉的候选者。第三,常数项-6.025的绝对值很大,当五个标志物全部正常时,Logit值接近-6,对应sigmoid函数计算出的患病概率约0.0024,模型先验上认为全阴性样本基本是良性,这符合临床预期。sigmoid函数的形式就是P(y=1|x;θ)=1/(1+e^(-θᵀx)),θ通过最大似然估计求解,论文里的对数似然函数写作Σ[ylog(g(θᵀx))+(1-y)log(1-g(θᵀx))]。
2.5 分类表:从85.6%到91.3%的边际贡献
论文分类表展示了逐步加入变量后对训练样本的预测效果:第一步准确率85.6%,第二步90.0%,到第七步达到91.3%。这个递进过程本身就是向前法价值的最好证明——你不仅能看到最终结果,还能看到每个变量的边际贡献。对照组识别率从第一步的100%到最后94.3%略有下降,实验组识别率从74.4%提升到88.9%。如果你在复现时发现某一步加入变量后总准确率反而下降,通常说明该变量与已在方程中的变量存在共线性,或者它的诊断信息已经被其他变量覆盖。这时不要强行保留该变量,让筛选流程自己决定去留,人为干预只会破坏统计口径的一致性。
3. LR、SVM、BP三类模型同台对比:160例样本上的真实诊断表现
3.1 三个模型的建模逻辑差异:线性概率、最大间隔与非线性拟合
论文在筛选出5个标志物之后,分别用LR、SVM和BP神经网络建模,比较分类效果。三个模型的理论出发点完全不同:LR是线性模型,输出的是明确的患病概率,系数有统计推断意义;SVM是最大间隔分类器,目标是在特征空间里找一个最大化支持向量间隔的超平面,并通过核函数隐式映射到高维空间;BP神经网络是多层感知机加反向传播,理论上能拟合任意非线性函数,但参数多、对样本量要求高。放在同一个数据集上对比,本质上是在问同一个问题:面对同样的5个二值化标志物,哪种建模策略最能刻画良恶性之间的边界?
3.2 实验设置与结果总览
论文的样本结构是90例结直肠癌患者和70例健康对照,共160例。SVM用70例恶性样本和50例健康样本共120例做训练,剩下20例恶性加20例健康做测试;BP同样按120/40划分。ROC曲线和AUC的评价范围覆盖全部160例样本。具体结果汇总如下:
| 模型/指标 | 样本范围 | 评估方式 | AUC / 准确率 |
|---|---|---|---|
| CEA单项 | 160例 | ROC | AUC=0.828 |
| CA724单项 | 160例 | ROC | AUC=0.760 |
| CA242单项 | 160例 | ROC | AUC=0.773 |
| CA153单项 | 160例 | ROC | AUC=0.697 |
| HSP60单项 | 160例 | ROC | AUC=0.775 |
| LR五指标联合 | 160例 | ROC | AUC=0.957 |
| SVM五指标 | 120训练+40测试 | 准确率 | 85.0%(34/40) |
| BP五指标 | 120训练+40测试 | 准确率 | 62.5%(25/40) |
单项AUC全部落在0.697到0.828之间,属于“有一定准确性但不够好”的水平;LR联合模型0.957直接进入高诊断价值区间。SVM和BP的准确率差异很大,原因在后面单独拆解。
3.3 LR模型AUC=0.957是怎么来的:联合检测的增益逻辑
从数据上看,五个单项标志物里最好的CEA也只有AUC=0.828,简单取任何一个做诊断都会漏掉不少病例。LR联合模型做的事情,本质上是给五个标志物的异常状态分配权重,让“几个指标同时异常”这种情况在概率排序里获得更高的位置。举个例子,一个患者CEA和CA724同时阳性,另一个患者只有CEA阳性,LR模型会通过加权求和把前者的Logit值拉得更高,从而在ROC曲线上获得更靠左上角的点。这就解释了为什么AUC能从0.828跳到0.957——联合检测把五个弱相关信号叠加起来,比任何一个单一信号都接近病理真相。这也是论文结论里“联合检测有助于提高灵敏度”的数学来源。
3.4 为什么SVM和BP在这个场景里反而不如LR
SVM准确率85%其实不低,BP只有62.5%,LR的AUC则最高。这个结果乍一看反直觉,拆开看有三个原因。第一,LR在这里做的是“联合检测”的天然任务——5个标志物的线性加权求和本身就是临床上联合检测的数学形式,模型假设和数据生成机制是匹配的;SVM虽然也是线性超平面,但它输出的是距离决策面的距离而不是概率,在AUC这种基于排序的评估口径上天然吃亏。第二,BP只有120个训练样本,却要同时学习输入层到隐含层再到输出层的全部连接权重,隐含层节点稍多就过拟合,稍少又欠拟合,论文里62.5%的准确率比随机猜测好不了多少,就是典型的样本量撑不起模型复杂度。第三,SVM和BP的分类边界都是“硬”决策,没有像LR那样显式建模概率,当正负类在特征空间重叠较多时,硬边界的泛化能力反而不如概率模型。所以这三个模型的结果放到一起,恰好印证了机器学习里“先看数据量再选模型复杂度”的基本原则。
4. 数据预处理与实验设计:二值化编码、训练测试划分与ROC评估
4.1 样本入组标准与检测平台
论文样本来自2014年3月至2015年3月在郑州大学第一附属医院消化科进行结直肠癌手术治疗的患者90例,均经手术及病理学明确诊断,影像学检测及术中探查证实无其他组织脏器转移;健康对照组为同期体检健康者70例。血清标志物检测使用罗氏Cobas6000全自动生化免疫分析仪,酶联免疫法,原装配套试剂盒。有两个细节对复现很重要:一是病理确诊是金标准,标签Y的可信度很高;二是转移患者被排除了,避免转移灶干扰标志物水平。如果你的数据来自病历系统,这两条是首先要核对的入组标准,标签质量直接决定模型评估有没有意义。
4.2 二值化编码规则与反向指标处理
检测水平超过临界值判为阳性赋值为1,低于临界值判为阴性赋值为0;UGT1A8反向处理。编码规则在代码里建议写成显式映射,方便逐指标核对:
python
二值化编码:正常=0,异常=1
UGT1A8是低值阳性:低于临界值才是阳性
def encode_biomarker(value, lower, upper, reverse=False): """ reverse=False: 低于lower或高于upper视为异常 reverse=True: 仅低于lower视为异常(UGT1A8场景) """ if reverse: return 1 if value < lower else 0 abnormal = (value < lower) or (value > upper) return 1 if abnormal else 0
逻辑说明:encode_biomarker接收检测值、参考范围上下限和反向标记,返回0或1。核心思路是把“是否异常”这个临床语义转换成模型输入,而不是直接塞原始浓度。reverse参数单独处理UGT1A8这种低值阳性指标,其余17种指标走统一的双向异常判断。
参数说明:lower和upper来自试剂盒说明书上的参考范围,不同批次试剂可能微调,建模前要重新核对;reverse必须逐指标确认,最稳妥的做法是分组统计每个指标在癌症组和对照组的均值,低值阳性指标在癌症组中检测值反而更低,一眼就能识别出来。
4.3 训练集与测试集划分:120/40背后的平衡问题
SVM和BP都用120例训练、40例测试,训练集里恶性70例、健康50例,测试集里恶性20例、健康20例。这个划分有几个隐藏问题值得注意。第一,训练集里恶性样本明显多于健康样本(70:50),而测试集是1:1,模型在训练时见过更多正类样本,测试时正负类先验却完全平衡,如果模型倾向预测正类,测试准确率会被50%的负类样本拉低。第二,论文没有说明划分是随机还是按入组顺序,如果是随机划分,必须固定随机种子才能复现;如果不固定,小样本下每次划分换掉几个人,分类边界就会明显变化。第三,40例测试集只占全量的25%,差一例判错就是2.5个百分点的准确率波动,SVM的85%和BP的62.5%之间隔着9个样本,放到置信区间里看差距比直觉上大得多。
4.4 ROC曲线与AUC的判断标准
论文用ROC曲线下面积AUC评价诊断价值,标准很明确:AUC在0.5~0.7之间为较低准确性,0.7~0.9之间有一定准确性,0.9以上诊断效果较好。五个单项标志物的AUC从0.697到0.828,LR联合模型0.957。这里要提醒一句,AUC的置信区间在样本量不大时会比较宽,论文表4显示CEA的95%置信区间是0.757~0.899,HSP60是0.703~0.848。看到这种区间就应该明白,单项指标之间0.05左右的AUC差异其实并不一定有统计学显著性,比较两个模型时除了看AUC点估计,最好同时看置信区间,或者用DeLong检验算一下差异的P值。
4.5 复现时的交叉验证建议
由于论文没有公开数据,复现时只能自己构造或获取类似数据。我一般会建议把论文的单次划分改成5折交叉验证,这样每个样本都有机会进测试集,评估结果更可靠。特别是对160例这种规模,交叉验证的标准差能直接回答“85%和62.5%的差距到底可不可信”。另外,交叉验证里要把二值化编码放在训练集内部计算临界值,而不是用全局临界值——虽然论文用的是试剂盒固定的临界值不存在这个问题,但如果你从原始浓度自己定义异常界限,就必须在每一折里重新计算,否则会引入轻微的数据泄露。
5. 避坑指南:小样本建模中五个反复出现的翻车点
5.1 反向指标编码错误导致模型系数方向颠倒
现象:某个特征在模型里的系数是负的,但临床直觉和文献都说这个指标升高提示恶性。 原因:像UGT1A8这种低值阳性的指标,如果按常规“高值为异常”编码,异常信号被反转,模型学到的关系自然与真实方向相反。 解决:编码前先做方向检查,分组统计每个指标在癌症组和对照组的均值或阳性率。低值阳性指标在癌症组里的检测值应该更低,如果发现方向不对,检查试剂盒说明书的阳性判定标准,在代码里用reverse参数单独处理。这个检查花两分钟,能避免后面所有下游结论全部作废。
5.2 训练集与测试集划分没有固定随机种子
现象:同一份数据,每次运行结果不一样,有时SVM准确率80%,有时90%。 原因:小样本下随机划分训练测试集会带来可观的波动,120个训练样本里换掉几个人,分类边界就变了。 解决:划分前固定随机种子,比如train_test_split里的random_state=42;更稳妥的做法是做5次重复划分取平均准确率,论文里的85%很可能就是单次划分的结果,复现时用多次划分均值更客观。
5.3 BP神经网络的隐含层节点数是门玄学
现象:BP在训练集上准确率很高,测试集只有62.5%,训练测试差距悬殊。 原因:BP的拟合能力太强,120个样本对几十个连接权重来说根本不够,隐含层节点一多就过拟合,一少又欠拟合。节点数没有通用的解析公式,只能靠实验。 解决:如果坚持用BP,先把输入特征降维到3个以内再试,或者干脆用MLPClassifier配合正则化参数调优;如果目标是临床诊断而不是复现论文对比,在这个样本量下直接放弃BP换LR或SVM更实际。
5.4 SVM的核函数和C值没调参就直接跑
现象:SVM准确率85%,看起来不错,但不知道是不是最优配置,换一组核函数可能结果完全不同。 原因:论文没详细说明SVM用的是线性核还是RBF核,也没提C值。不同核函数在小样本下的差异很大——线性核等价于逻辑回归的决策边界,RBF核能拟合更复杂的边界但更容易过拟合。 解决:用网格搜索加交叉验证选核函数和C,比如在[0.1, 1, 10]里选C,在['linear', 'rbf']里选核函数。160例这种规模的数据,几分钟就能跑完,别偷懒直接默认参数。
5.5 只看准确率不看AUC容易被误导
现象:BP准确率62.5%,SVM准确率85%,如果只报告准确率,结论是SVM远好于BP。 原因:准确率依赖分类阈值,在0.5阈值下恰好BP输得比较多;而且40例测试集里一例判错就是2.5个百分点,准确率在小测试集上的波动远大于AUC。 解决:同时报AUC、灵敏度、特异度。AUC不依赖阈值,更能反映模型排序能力;灵敏度对应“癌症患者被正确识别的比例”,特异性对应“健康人被正确识别的比例”,论文里联合检测提高的正是灵敏度。如果要跟论文对比结论,按论文口径同时算AUC和准确率,两个指标都对得上才算复现成功。
6. 复现路径:用Python把LR-SVM-BP筛选与建模流程跑通
6.1 最小复现代码框架
论文没有公开代码,但整个流程在Python里可以完整实现。核心三步:二值化编码、逐步LR筛选、三个模型对比。下面给一个最小框架。
python import numpy as np import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.neural_network import MLPClassifier from sklearn.metrics import roc_auc_score, accuracy_score from sklearn.model_selection import train_test_split import statsmodels.api as sm
假设df包含18个标志物检测列和目标列y(1=癌症,0=对照)
markers = ['CEA', 'CA50', 'HSP60', 'CYFRA21-1', 'TPA', 'AFP', 'CA199', 'CA242', 'CA724', 'CA125', 'CA153', 'UGT1A8']
def encode_biomarker(value, lower, upper, reverse=False): if reverse: return 1 if value < lower else 0 abnormal = (value < lower) or (value > upper) return 1 if abnormal else 0
binary_data = pd.DataFrame(index=df.index) for m in markers: binary_data[m] = df[m].apply( lambda v: encode_biomarker(v, lower[m], upper[m], reverse=(m == 'UGT1A8')) )
def forward_lr(X, y): remaining = list(X.columns) selected = [] last_aic = sm.Logit(y, sm.add_constant(X[remaining])).fit(disp=0).aic while remaining: best_aic, best_feat = np.inf, None for feat in remaining: cols = selected + [feat] model = sm.Logit(y, sm.add_constant(X[cols])).fit(disp=0) if model.aic < best_aic: best_aic, best_feat = model.aic, feat if best_aic >= last_aic: break selected.append(best_feat) remaining.remove(best_feat) last_aic = best_aic return selected
selected = forward_lr(binary_data[markers], df['y']) print('LR筛选结果:', selected)
X = binary_data[selected] y = df['y'] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.25, random_state=42, stratify=y ) models = { 'LR': LogisticRegression(max_iter=1000), 'SVM': SVC(kernel='rbf', C=1.0, probability=True), 'BP': MLPClassifier(hidden_layer_sizes=(4,), max_iter=2000, random_state=42) } for name, model in models.items(): model.fit(X_train, y_train) prob = model.predict_proba(X_test)[:, 1] pred = model.predict(X_test) print(f"{name}: AUC={roc_auc_score(y_test, prob):.3f}, " f"ACC={accuracy_score(y_test, pred):.3f}")
逻辑说明:forward_lr用AIC作为逐步筛选准则,AIC不再改善就停止,结果和论文的条件似然比检验在特征选择方向上一致。三个模型共用同一个训练测试划分,保证对比口径一致。
参数说明:SVC里probability=True是为了能输出概率从而计算AUC;MLPClassifier的hidden_layer_sizes=(4,)是保守的隐含层配置,论文里BP效果差很可能就是隐含层和训练轮数没调好;stratify=y保证训练测试集正负类比例一致。
6.2 两种输入口径的对照习惯
如果手里是原始浓度而不是0/1结果,建议两条路径都跑:二值化版本复现论文基准,浓度版本作为信息量增强的对照,对比两个版本筛出的特征组合是否一致。从那以后我每次接到肿瘤标志物建模的需求,都强制先逐指标确认阳性方向,再做二值化与筛选,最后至少两个模型交叉验证对比。这套习惯就是从复现这篇论文的过程里养成的,模型可以换,但数据编码方向对不对这个问题,永远排在建模之前。希望帮到你。
本文还有配套的精品资源,点击获取