阿片复发风险的个体分层与可解释分类
摘要:本文针对美赛 2019-C 第二层问题——个体复发风险分类。基于 N=2000 名接受治疗者的合成队列(年龄均值 42.2 岁、日吗啡等效剂量 MME 均值 91.7 mg、总体复发率 55.8%),以 6 个可解释特征(年龄、日剂量、既往复发次数、治疗天数、共病、区域风险)构建标签。并行训练逻辑回归(可解释)与决策树 CART(非线性),均以 80/20 分层拆分评估。关键发现:复发率随既往复发次数由 0 次的 40.5% 单调升至 5 次的 84.1%,随区域风险由低到高由 47.5%→60.8%→69.7%;逻辑回归给出标准化系数 (OR=2.06)、(OR=1.65)、(OR=0.54,保护),测试集 AUC=0.755、准确率 66.8%;决策树 AUC=0.699、特征重要性以剂量(0.093)与治疗天数(0.054)居首。按真实风险分位,最低 25% 人群复发率仅 25.0%、最高 25% 高达 86.4%——风险高度集中。结论:既往史与用药强度是最强信号,模型可落地为"高危优先"的分层干预(图1—图8)。
关键词:逻辑回归;决策树;AUC;特征重要性;风险分层
一、问题重述
在识别出人群层面的时间序列后,第二层问题要求把视角下沉到个体:能否用治疗前的可获取特征,预测某位患者是否会在随访期内复发?这是一个典型的二分类问题,但竞赛更看重"可解释"与"可行动"——模型不仅要准,还要能告诉医生"为什么高风险""该盯住谁"。因此本文同时给出逻辑回归(系数即风险贡献)与决策树(路径即规则)两套互为补充的解法,并以 AUC、混淆矩阵、特征重要性多维度评估。
现实映射:美国许多州已建立"阿片用药审查"系统,医生在开方前能看到患者的用药史与风险评分。本文模型正是这类评分表的雏形——用 6 个字段即可快速排序风险,把有限的戒毒资源(床位、随访人力)投向最高危的 25% 人群。
具体落地形态是"用药前风险评分":医生在开具阿片处方前,系统依据患者年龄、既往史、共病等字段实时给出复发风险等级,对高危者自动触发更短复诊周期、同伴支持或减量方案。这类工具已在多州试点,其价值不只在准确率,更在"可解释、可审计、可嵌入既有诊疗流程"。
二、模型假设
- 每位患者有 6 个特征与 1 个二值复发标签,标签由潜在逻辑斯蒂概率抽样生成;
- 训练/测试按 8:2 分层随机拆分(种子固定),保证两类比例一致;
- 逻辑回归对特征做标准化(均值为 0、标准差为 1),系数可比;
- 决策树以 Gini impurity 为分裂准则,最大深度 4、叶最少 40 样本,防止过拟合;
- 以 0.5 为默认判定阈值;所有随机性由种子 2019+ 派生,可复现。
三、符号说明
| 符号 | 含义 |
|---|---|
| 第 个特征(标准化后) | |
| 逻辑回归标准化系数 | |
| OR | 优势比 |
| AUC | 受试者工作特征曲线下面积 |
| Gini | 基尼不纯度(树分裂准则) |
四、模型的建立
4.1 逻辑回归(可解释主干)
以梯度下降估计 ,输出概率即风险评分;系数符号与大小直接给出"每升高 1 个标准差,复发对数优势的变化",指数化得 OR。逻辑回归的优势在于参数可直接解释:系数符号即方向、指数化即相对风险,医生无需理解机器学习即可读懂;其代价是假设特征经标准化后线性,对强非线性交互表达力有限——这正是并行训练决策树的理由。
4.2 决策树 CART(非线性补充)
递归按 Gini impurity 下降最大处二分,直到深度/叶样本数触限或节点纯。叶输出该节点阳性比例作为风险概率。树的分裂路径可转写为临床规则(如"剂量>某阈 且 既往复发≥某次 → 高危"),特征重要性由分裂累计的 Gini 下降量度量。一棵深度 4 的树可被完整打印为"若 A 且 B 则高危"的若干条规则,护士与社工也能照章操作;这点在资源紧张、难以部署复杂系统的基层尤为关键。
4.3 评估指标
除准确率外,重点采用 AUC(对不平衡与阈值不敏感,衡量排序能力)与混淆矩阵(区分假阳/假阴的政策代价)。对复发预测,假阴(漏掉高危者)的代价远高于假阳,故 AUC 比准确率更关键。
五、模型求解与结果
- 数据画像:2000 人中复发 1116 人(55.8%)。复发率随既往复发次数单调攀升:0 次 40.5% → 1 次 51.1% → 2 次 60.5% → 3 次 70.5% → 4 次 77.9% → 5 次 84.1%;随区域风险 47.5%→60.8%→69.7%(图1)。
- 逻辑回归系数(图2):既往复发 0.721(OR 2.06,最强正向)、日剂量 0.500(OR 1.65)、区域风险 0.466(OR 1.59)、共病 0.243(OR 1.28)、年龄 0.276(OR 1.32)、治疗天数 −0.625(OR 0.54,保护)。即"多一次既往复发,复发对数优势 +0.72;治疗每多 1 个标准差,风险降约一半"。
- 判别力:逻辑回归测试集 AUC=0.755、准确率 66.8%(混淆:TN=121, FP=56, FN=77, TP=147);决策树 AUC=0.699、准确率 66.8%(TN=72, FP=105, FN=28, TP=196)。逻辑回归排序更优,决策树召回更高(漏诊更少)。
- 特征重要性(图3):决策树给出剂量(0.093)、治疗天数(0.054)、年龄(0.045)、区域(0.043)、既往(0.035)——与逻辑回归"既往/剂量最强"的结论相互印证,只是树更看重剂量。
- 风险集中(图7):按真实风险分位,最低 25% 人群复发率仅 25.0%、最高 25% 高达 86.4%,相差逾 3 倍。
六、结果分析与灵敏度
- 既往史是最强信号:OR=2.06 意味每多 1 个标准差的既往复发次数,复发优势翻倍——与图1 单调上升一致,是临床直觉的量化。
- 治疗天数是保护因素:OR=0.54,说明足够长的规范治疗显著降低复发,是"可干预"的抓手。
- 剂量双刃:高 MME 提升复发风险(OR 1.65),呼应"高剂量→耐受→过量"的病理链,支持处方量管控。
- 两模型互补:逻辑回归 AUC 更高(排序更稳),决策树召回更高(FN 仅 28 vs 77),实践中可"树初筛 + 逻辑回归精排"。
- 准确率天花板合理:55.8% 患病率下全猜阳性仅 55.8%,模型提升至 66.8% 且 AUC 0.755,属"中等偏强"判别力,符合真实复发预测的客观难度(图6)。
- 风险集中可用于资源分配:最高 25% 人群占 86.4% 复发,意味着把随访资源集中于该层即可覆盖大部分事件——量化了"精准干预"的杠杆。
- 阈值应按代价调:复发预测中漏诊(假阴)代价远高于误报(假阳)——漏掉的高危者可能致命,误报仅多一次随访。当前 0.5 阈值偏保守,将判定阈值下移至约 0.4 可进一步提升召回(决策树 FN 由 28 继续下降),代价是更多随访投入,需依预算权衡。
- 可解释性即可落地性:逻辑回归系数与决策树路径都能直接写进临床规则(如"既往≥3 次 或 剂量≥某阈 → 标记高危"),比黑箱模型更易被医生采纳与审计,也便于监管回溯。
七、模型评价
优点:(1) 逻辑回归 + 决策树"双轨"兼顾可解释与高召回;(2) 用 AUC 与混淆矩阵多维度评估,避免单看准确率;(3) 特征标准化使系数可比、OR 可直接对外沟通;(4) 纯标准库实现、种子固定,可复现。两种方法均不依赖外部库、可在普通笔记本秒级训练,便于作为教学与基层推广原型。
局限:(1) 标签由简化逻辑斯蒂生成,未含未观测混杂;(2) 决策树深度受限,可能漏掉高阶交互;(3) 未做交叉验证,仅单次拆分;(4) 阈值 0.5 未必最优,应按"漏诊代价"下调阈值提召回。
八、结论
个体复发风险可由 6 个常规字段有效排序:既往复发史与用药剂量是最强正向信号,规范治疗时长是最强保护因素;逻辑回归 AUC 0.755、决策树召回更高,二者互补。最关键的落地结论是风险高度集中——最高危 25% 人群复发率达 86.4%,据此实施"高危优先"的分层随访,能以最小资源覆盖最多事件。换言之,模型输出的不是"是否会复发"的定论,而是"该投入多少关注"的优先级排序——这是公共卫生资源稀缺下的理性用法。
九、管理建议(落地指引)
将模型转化为日常分诊工具,需要配套四项落地机制。第一,把风险评分做成开方前的强制弹窗:医生在处方任何阿片类药物前,系统自动调取患者近一年的用药史、剂量与既往复发记录,给出红黄绿三色风险灯,红灯患者须附理由才能开方。第二,按风险分位实施差异化随访:对最高危的百分之二十五人群,配置每月一次上门随访与药物辅助治疗,对低危人群则转为季度短信提醒,把有限人力从低风险群体释放出来。第三,设置动态阈值而非固定零点五:考虑到漏诊一名高危患者代价远高于误报,建议把判定阈值下调至约零点三,以召回率为优先换取更高的真实阳性捕获。第四,建立模型问责与再训练制度:每季度用新发病例回测评分准确率,当 AUC 跌破约定下限时触发人工复核与特征更新,防止模型因人群结构变化而悄悄失效。这四条建议把"排序"真正变成"行动",让统计概率落地为救人的资源调度。
附录:核心 Python 实现
# 附录:核心 Python 实现(独立可运行,复现本文权威数字)
import os, sys, random
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(os.path.join(_HERE, "..", "..", "..", "tools")))
import gen_mcm2019c as G
D = G.gen_mcm2019c()
c = D["cls"]
print("N=%d 训练=%d 测试=%d 患病率=%.3f" % (c["N"], c["Ntrain"], c["Ntest"], c["prevalence"]))
print("逻辑回归系数:", {k: round(v, 4) for k, v in c["logit_coef"].items()})
print("OR:", {k: round(v, 3) for k, v in c["odds_ratio"].items()})
print("Top因素:", [(n, round(v, 4)) for n, v in c["top_factors"]])
print("逻辑回归: AUC=%.4f acc=%.4f" % (c["logit_test"]["auc"], c["logit_test"]["acc"]))
print("逻辑回归混淆=", c["logit_test"]["confusion"])
print("决策树: AUC=%.4f acc_train=%.4f acc_test=%.4f" % (
c["tree"]["auc"], c["tree"]["acc_train"], c["tree"]["acc_test"]))
print("决策树混淆=", c["tree"]["confusion"])
print("决策树特征重要性:", {k: round(v, 4) for k, v in c["tree"]["importance"].items()})
# 高危/低危亚组复发率(按真实风险分位)
rows = G._gen_patients(random.Random(G.SEED))
zs = sorted(((G.B0 + G.BETA["age"]*r["age"] + G.BETA["dose_mme"]*r["dose_mme"]
+ G.BETA["prior_relapses"]*r["prior_relapses"] + G.BETA["treatment_days"]*r["treatment_days"]
+ G.BETA["comorbidity"]*r["comorbidity"] + G.BETA["region_risk"]*r["region_risk"],
r["relapsed"]) for r in rows), key=lambda x: x[0])
q = len(zs)//4
print("低危25%%复发率=%.1f 高危25%%复发率=%.1f" % (
sum(r for _, r in zs[:q])/q*100, sum(r for _, r in zs[-q:])/q*100))