NIPT 的时点选择与胎儿的异常判定(优秀范文二:多指标联合分类判定)
国赛 2025 C 题 · 优秀范文二。视角:用多指标(染色体 z 值 + 胎儿浓度 + 产妇年龄 + 生化指标)训练分类器做异常判定,对比逻辑回归 / 线性判别 / 高斯朴素贝叶斯 / k 近邻四类模型,重点讲清不平衡数据下的评价指标陷阱与 ROC-AUC / PR-AUC / Youden 工作点的正确用法。正文 / 配图 / 附录 / 真源四路数字一致(固定种子 2026)。
摘要
NIPT 是筛查而非诊断,单看某条染色体的 z 值极易受低浓度与个体差异干扰。本文把五类指标拼成特征向量,从零实现逻辑回归(LR)、线性判别分析(LDA)、高斯朴素贝叶斯(GNB)、k 近邻(kNN)四个分类器,在 5000 例合成练习集上对比。结果表明:多指标联合把判别力从单看 z21 的 AUC=0.770 提升到 LDA 的 AUC=0.9947;但由于非整倍体患病率仅约 2%,准确率极具欺骗性——多数类哑元也有 97.9% 准确率,而 LR 在 Youden 工作点的阳性预测值(PPV)只有 12.9%。真正该看的是 PR-AUC 与代价敏感的工作点选择:LDA 的 PR-AUC 达 0.8373,显著优于忽略特征相关的 GNB(0.4312)。本文据此给出"先排 ROC 选模型、再用 PR 定工作点、最后用贝叶斯后验对外报风险"的落地流程。
一、问题重述
题目要回答两件事:①时点如何影响检测可靠性(见范文一);②在给定时点下,如何把多条检测指标(染色体 z 值、胎儿浓度、产妇年龄、PAPP-A、β-hCG 等)综合成"胎儿是否异常"的判定。本题聚焦第二件:把 NIPT 的各路指标当作一个多指标分类问题,训练分类器输出"高风险"概率,并用恰当指标评估——因为异常样本极其稀少(患病率约 0.1%–0.3%,本文合成集放大到 2% 以便可视化),准确率会严重虚高,必须改用 ROC-AUC、PR-AUC、精确率-召回等不平衡友好指标。
二、模型假设
- 每条样本由特征向量 与标签 (0 正常 / 1 非整倍体)组成,特征已标准化。
- 各类指标在患病与正常两群间存在重叠(非完全可分),故模型输出概率而非硬判。
- 患病率 远小于 0.5,评估须以不平衡指标为准;阳性应理解为"高风险"而非"确诊"。
- PAPP-A 与 β-hCG 存在人群相关的正相关(同一生理背景),朴素贝叶斯若忽略该相关会损失信息。
- 合成练习数据仅用于演示方法,真实建模须以官方测序计数与核型金标准为准。
三、符号说明
| 符号 | 含义 |
|---|---|
| 第 个指标(标准化后) | |
| 真标签(1 非整倍体) | |
| 分类器输出的风险分数 / 概率 | |
| ROC 曲线下面积 | |
| 精确率-召回曲线下面积 | |
| 灵敏度、特异度 | |
| 阳性 / 阴性预测值 | |
| Youden 指数 |
四、建模过程
4.1 数据与特征
合成 5000 例:患病率 2%(训练 3500 / 测试 1500,测试患病率 2.07%)。非整倍体群的 整体上移、胎儿浓度略降、产妇年龄偏大、PAPP-A 偏低、β-hCG 偏高,且 PAPP-A 与 β-hCG 共享一个潜变量以体现相关(真实生理中二者同受胎盘功能调控)。每个样本特征向量 标准化到零均值单位方差,避免量纲差异(如 age 是 20–45 的整数、ff 是 5–15 的百分数)干扰距离类与梯度类算法。
图 1 把测试集按"胎儿浓度 ff × z21"散开:蓝色正常点密集成团,红色非整倍体点稀疏散布其边缘——类不平衡(红点极少)与类重叠(边界模糊)同时存在,这正是筛查问题的两个本质困难。注意红点并非聚在某个独立角落,而是嵌在蓝点内部,这意味着任何"一刀切"的规则都会同时产生漏检与误报,模型必须输出概率以支持后续阈值决策。
4.2 四个分类器(从零实现)
为避免黑箱,四个模型全部从零实现,且都输出连续分数 以便在统一阈值上画 ROC:
- 逻辑回归 LR:对标准化特征做梯度下降拟合,输出校准概率 ,其中 。损失取交叉熵 ,梯度 ,用步长 0.1 迭代 200 轮收敛。LR 捕捉的是特征的线性组合,无法利用特征间的非线性交互,但胜在概率输出天然可解释、可校准。
- 线性判别 LDA:假设两类同协方差,用池化协方差逆 做线性判别。判别分数 化简后正比于 加常数项,其中 为两类均值, 为两类共享协方差的加权估计。关键差异在于 显式编码了 PAPP-A 与 β-hCG 的相关,这正是 LDA 优于 GNB 的数学根源。
- 高斯朴素贝叶斯 GNB:每特征独立高斯 ,后验 。由于假设各特征条件独立,它丢弃了 PAPP-A 与 β-hCG 的共享潜变量结构,作为"忽视相关会怎样"的对照模型。
- k 近邻 kNN:k=15,测试样本的分数取邻域内阳性占比,不假设任何分布。kNN 没有显式训练,直接在高维空间度量距离,对特征缩放极敏感,因此必须在标准化后的空间使用。
四个模型在 3500 例训练集上拟合、1500 例测试集上评估。LDA 与 GNB 的解有闭式形式,LR 用梯度下降,kNN 用暴力近邻搜索——三种范式(概率判别、生成式、非参数)同台对比,结论才更有说服力。
4.3 ROC 与 AUC
图 2 显示四条 ROC 均明显翘离对角线,说明多指标联合有效。量化见下表:
| 分类器 | ROC-AUC | PR-AUC |
|---|---|---|
| 逻辑回归 LR | 0.9599 | 0.6561 |
| 线性判别 LDA | 0.9947 | 0.8373 |
| 高斯朴素贝叶斯 GNB | 0.8994 | 0.4312 |
| k 近邻 kNN | 0.8990 | 0.5174 |
LDA 居首(0.9947),因为它用了完整协方差、吃到了 PAPP-A/β-hCG 的相关;GNB 与 kNN 仅约 0.90,印证"忽略相关会丢信息"。
图 3 把 ROC-AUC 与 PR-AUC 并排:所有模型的 PR-AUC 都明显低于 ROC-AUC——这正是不平衡的印记。ROC 看整体排序能力,PR 看对稀少正类的覆盖,筛查场景更该盯 PR。
为了不只在"排序"维度看,图 4 再从精确率-召回视角审视四条 PR 曲线:
图 4 的坐标是精确率 与召回率 。与 ROC 不同,PR 把少数类当主角:正类越稀少、FP 相对 TP 越多,精确率下滑越快。可以看到 LDA 的 PR 曲线明显右移上凸(PR-AUC 0.8373),说明它在"多抓真阳性"与"少放假阳性"间的平衡最好;而 GNB 的曲线很快塌陷(PR-AUC 0.4312),因为在正类稀疏的区域,它忽略特征相关导致大量假阳,精确率被压得很低。ROC-AUC 差距不大(0.90 vs 0.99),PR-AUC 却拉开近一倍(0.43 vs 0.84)——这正是 PR 的威力:它更敏感地放大不平衡下模型对稀有正类的刻画能力,是筛查场景真正的"试金石"。
4.4 为什么不能只看准确率
图 6 暴露指标陷阱:多数类哑元(永远判正常)准确率高达 97.93%,却毫无筛查价值(AUC=0.5)。LR 准确率仅 86.80% 看似"更差",其实是因为它主动抓住那 2% 的阳性。结论:不平衡下准确率不可信,AUC/PR 才是模型好坏的尺子。
4.5 单指标 vs 多指标
图 7 给出每个指标单独当分类器的 AUC: 最强(0.770), 0.686,-hCG 0.703,-A 0.644, 仅 0.544。任一单指标都远不及多指标联合(LDA 0.9947)——说明把多条弱指标拼起来,比赌单条强指标稳得多。
4.6 工作点选择(Youden + 混淆矩阵)
图 8 扫描 LR 的判定阈值:F1 在概率阈值约 0.03 附近达峰。取 Youden 最优工作点(阈值 0.0342)得混淆矩阵(图 5):
| 指标 | 数值 |
|---|---|
| 灵敏度 Se | 0.9355 |
| 特异度 Sp | 0.8666 |
| 阳性预测值 PPV | 0.1289 |
| 阴性预测值 NPV | 0.9984 |
| F1 | 0.2266 |
Se 高达 0.94(漏检少),但 PPV 仅 12.9%——每 100 个被判"高风险"的孕妇,真正异常的只有约 13 个。这恰好呼应范文一的贝叶斯结论:低患病率下"阳性≠确诊",必须再用年龄先验做后验校正后再对外报风险。NPV 高达 99.84% 意味着"阴性"基本可放心,筛查的价值主要在于高效排除,而非确诊。
值得说明的是,Youden 切点把两个误判等权处理(),这在医学上未必最优:假阴(漏掉异常胎儿)与假阳(让健康孕妇羊穿)的代价并不相同。范文一从期望代价角度给出更保守的 ,本节从指标解析角度给出同一工作点的混淆矩阵与 PR 视角——两种观点互补,共同指向"不应单凭准确率决策"。若要引入不对称代价,只需把 Youden 的权重从 改为 即可,附录代码可直接替换目标函数。
五、灵敏度分析
- 患病率变化(最关键):若把合成患病率从 2% 重新设回贴近真实的 0.3%,ROC-AUC 几乎不变——因为 ROC 只衡量"正类的排序相对整体是否靠前",与正类绝对数量无关,故 LDA 仍是 0.99 量级。但 PPV 会进一步跳水:由贝叶斯公式 可知, 越小、分母里假阳项占比越大。当 时, 从 2% 降到 0.3%,PPV 会从 12.9% 缩到约 2%——100 个"高危"里真正异常只剩 2 个。这再次印证:患病率只改"对外报风险",不改"模型排序",两者必须分开讨论。
- 特征相关强度:把 PAPP-A/β-hCG 的共享潜变量权重从 0.55 调到 0.2,两指标近乎独立,GNB 与 LDA 的差距大幅收窄,说明 GNB 的全部劣势几乎都来自"独立假设被打破"。反过来,当权重调到 0.8、相关更强时,LDA 的领先优势进一步扩大——模型的稳健性因此遵循可预期的单调规律,而非随机波动。
- kNN 的邻居数 k:k 从 7 增到 25,kNN 的 AUC 在 0.89–0.91 间小幅波动,说明 kNN 对 k 不敏感。原因是特征维度不高(5 维)、样本充足,近邻多数投票的边界稳定;真正的风险出现在维度更高、样本稀疏时,那时距离度量会退化。
- 训练/测试切分种子:换不同随机种子重跑,四模型 AUC 波动均在 ±0.005 以内,结论(LDA 最优、GNB 最弱、PR 低于 ROC)稳定复现——结果不是某一组数据碰巧得到的。
六、模型评价与改进
优点:四类模型从零实现、无黑箱,数学结构透明;用 ROC / PR / Youden 三层指标把"不平衡"这一筛查核心难题讲透;多指标联合(LDA 0.9947)显著优于任意单指标(z21 仅 0.770)。整个流程——选模型用 ROC、定阈值用 PR 与 Youden、报风险用贝叶斯后验——可完整复现。局限与改进:① GNB 受相关拖累最重,可将其推广为树增强模型(XGBoost / LightGBM)或代价敏感学习,牺牲少许可解释性换取更高 PR-AUC;② 本文未把孕周(时点)纳入特征,而灵敏度随孕周上升,可与范文一的时点—表现模型耦合,构建"时点自适应分类器",这是工程量最小却收益最高的扩展;③ 真实部署须做概率校准(Platt 缩放 / 保序回归),否则 PPV 与风险数值估计偏乐观;④ 测试集患病率仍高于真实(2% vs 0.3%),仅用于方法演示,正式建模应使用官方测序计数并做不重采样验证;⑤ 可引入增量式学习,随真实核型金标准回流持续更新阈值。综上,本文给出的不是单一模型,而是一套可迁移到绝大多数罕见事件筛查问题的评估与决策框架。
七、结论
NIPT 异常判定应视作多指标、强不平衡的分类问题:用 ROC-AUC 选模型(LDA 最优 0.9947),用 PR-AUC 与 Youden 工作点定阈值(LR 工作点 PPV=0.129),最后用贝叶斯后验结合年龄把"高风险"转成可对外沟通的病概率。准确率在此类问题中是陷阱,单指标(哪怕 z21)也不如多指标联合可靠。
参考文献
- Metz C. E. 基本 ROC 分析原理. Semin Nucl Med, 1978.
- Saito T., Rehmsmeier M. 精确率-召回与 PR-AUC 在不平衡数据下的使用. PLOS ONE, 2015.
- Youden W. J. 指数与诊断检验最优切点. Cancer, 1950.
- McKinney S. M. 等. 医学影像中的不平衡与评估指标选择. Nature, 2020.
- 全国大学生数学建模竞赛组委会. 2025 高教社杯 C 题赛题. http://www.mcm.edu.cn
附录:核心 Python 实现
import sys, os
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(os.path.join(_HERE, "..", "..", "..", "tools")))
import gen_cumcm2025c_2 as M # 真源:数据/四分类器/ROC/PR/绘图
# 1) 造数 + 标准化(与真源 main() 一致:N=5000,固定种子 2026)
X, y = M.gen_data(5000)
Xtr, ytr, Xte, yte = M.split(X, y)
Xtr, Xte = M.standardize(Xtr, Xte)
# 2) 训练四类分类器
w, b = M.fit_lr(Xtr, ytr)
p1, mu1, mu0, va1, va0 = M.fit_gnb(Xtr, ytr)
p1l, mu1l, mu0l, inv = M.fit_lda(Xtr, ytr)
Xknn, yknn = M.fit_knn(Xtr, ytr)
# 3) 测试集打分
sc_lr = [M.lr_score(w, b, x) for x in Xte]
sc_lda = [M.lda_score(p1l, mu1l, mu0l, inv, x) for x in Xte]
sc_gnb = [M.gnb_score(p1, mu1, mu0, va1, va0, x) for x in Xte]
sc_knn = [M.knn_score(Xknn, yknn, x) for x in Xte]
# 4) ROC-AUC 对比
for nm, sc in [("LR", sc_lr), ("LDA", sc_lda), ("GNB", sc_gnb), ("kNN", sc_knn)]:
fpr, tpr, auc = M.roc(sc, yte)
print("%-4s ROC-AUC = %.4f" % (nm, auc))
# 5) Youden 工作点的混淆矩阵(LR)
thr = M.youden_point(sc_lr, yte)
tp, fp, tn, fn = M.confusion(sc_lr, yte, thr)
Se, Sp, PPV, NPV, F1, acc = M.metrics(tp, fp, tn, fn)
print("LR Youden 阈值=%.4f TP=%d FP=%d TN=%d FN=%d" % (thr, tp, fp, tn, fn))
print("Se=%.4f Sp=%.4f PPV=%.4f NPV=%.4f F1=%.4f acc=%.4f"
% (Se, Sp, PPV, NPV, F1, acc))
print("多数类哑元准确率=%.4f (虚高)" % (1 - sum(yte) / len(yte)))