ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HFD评分:纤维蛋白原与D-二聚体预测肿瘤预后模型复现

HFD评分:纤维蛋白原与D-二聚体预测肿瘤预后模型复现 朋友转给我一篇哈医大学者发的肿瘤预后预测文章IF 13一区Top最亮眼的是他们构建的新型指标HFD。我第一反应是“又一个列线图模型”但读完Method才发现这个HFD不是高脂饮食而是基于纤维蛋白原和D-二聚体两个常规凝血检验指标构建的复合评分0到2分简单到极致。真正高明的地方在于他们把“凝血指标肿瘤预后”这个老话题用一套标准化的预测模型流程重新包装讲进了一区。这种文章最值得复现的地方不是某个复杂算法而是整体研究框架低成本变量、清晰的建模流程、齐全的验证图表。哪怕你没有哈医大的病例数据只要手里有一份随访完整的队列数据就能把这个流程完整跑下来。这篇我边读边还原了整套做法还会把R代码、常见报错、审稿人容易挑的统计毛病一起整理出来适合正在做临床预测模型的研究生也适合想低成本发文的临床医生参考。1. 被标题吸引之前先搞懂HFD到底是什么1.1 先解开第一个误会HFD不是高脂饮食很多人在PubMed检索时会把HFD自动识别成high-fat diet第一眼根本想不到这是一篇临床预后研究。实际上在这个研究里HFD是研究者自己定义的凝血相关组合评分High Fibrinogen and D-dimer score分别代表纤维蛋白原和D-二聚体是否升高。两个指标都是凝血功能检验里的常规项目一台全自动凝血分析仪就能同时出结果。具体构造方式也很朴素术前采集患者外周血测定血浆纤维蛋白原FIB和D-二聚体D-dimer水平用最佳截断值把每个连续变量转换成二分类变量满足条件记1分否则记0分两项相加得到0、1、2分。这种赋分方式在预测模型里很常见好处显而易见临床医生看门诊时不需要算任何公式数一下几个指标超标就能快速分层可解释性极强。不过这里有一个容易被忽略的细节为什么偏偏选纤维蛋白原和D-二聚体而不是白蛋白、中性粒细胞这些同样便宜的项目这和肿瘤患者的凝血状态有关。很多恶性肿瘤患者存在血液高凝状态肿瘤细胞可以激活凝血级联反应导致纤维蛋白原合成增加同时纤溶系统被激活后交联纤维蛋白降解产生D-二聚体。这两个指标本质上反映的是同一条病理通路的两端——凝血激活和纤溶亢进单独用任何一个都容易受感染、外伤等因素干扰组合起来反而能互相印证。1.2 为什么“常规指标预后模型”还能发一区说句实在话纤维蛋白原和D-二聚体与肿瘤预后的关系并不是新发现几十年前就有人在肝癌、胃癌、结直肠癌里报道过。那为什么哈医大团队还能凭这个思路发到IF 13我读完以后觉得主要是三层增量。第一层增量是分析角度过去很多研究只报道“纤维蛋白原升高提示预后差”这种单因素结论这篇直接把它做成了可供临床使用的分层工具而且做了完整的模型验证包括训练集与验证集划分、时间依赖ROC、校准曲线、决策曲线分析。这种规范化程度远高于十几年前的同类文章。第二层增量是机制与临床场景的匹配。他们选择的瘤种非常合适肝癌本身容易合并肝硬化、门静脉高压和凝血功能障碍纤维蛋白原和D-二聚体在肝癌人群里的变异度大预后区分度自然更明显。如果换成甲状腺癌这种整体预后极好的瘤种就算指标构建得再漂亮也很难做出差异这说明研究对象的选择本身就是一项科研设计能力。第三层增量是切合临床痛点。肝癌术后复发转移风险高影像学随访存在滞后性患者最需要的其实是术后能定期监测的血液指标。凝血功能检查价格便宜、普及率高、基层医院也能做比起miRNA、ctDNA这些昂贵的检测推广门槛低得多这种落地价值是高分期刊非常看重的卖点。2. 高分思路拆解HFD研究是怎么设计的2.1 研究终点和人群定义是模型的地基我对复现这类研究的第一个建议是先不要急着打开R乱跑把临床问题定义清楚。从原文的逻辑来回推这个研究大概率做的是肝细胞癌根治术后患者的预后预测主要终点是总生存期OS次要终点可能是无复发生存期RFS。随访时间的起点通常是手术日期终点是死亡或最后一次随访日期单位统一用月。人群的纳入排除标准决定了数据质量的上限。我根据自己的整理梳理了一个可复制的标准模板基本可以把常见偏倚全部卡掉纳入标准经病理确诊的原发性肝细胞癌接受根治性手术术前有完整的凝血功能检测记录临床病理资料和随访信息完整。排除标准术前接受过抗凝治疗合并其他恶性肿瘤围手术期发生严重感染或输血随访信息缺失或失访比例过高术前接受过TACE、放疗或靶向治疗。这里最需要注意的是“术前凝血指标”这个时间点。临床病历系统里往往既有入院次日抽血结果还有术前准备时的复查结果如果你两种混用指标会引入大量噪声。正确做法是固定取手术日期前7天内距离手术最近的一次结果如果该期间发生过输血或抗凝治疗直接视为缺失或排除。2.2 复合指标怎么造连续变量到赋分评分的转化逻辑HFD的构建核心在于把FIB和D-dimer从连续变量变成二分类变量。很多人会直接用正常值上限做截断比如FIB超过4.0 g/L、D-dimer超过0.5 mg/L就记1分这个方法简单但不够严谨。高分文章普遍采用的方案是用最佳截断值法在生存数据上扫描所有可能的切点选择能够最大程度区分生存差异的取值。具体到R代码实现我用的是survminer包里的surv_cutpoint函数。它计算每个候选截断值的对数秩统计量或基于协变量调整后的P值可以设定minprop 0.3防止切点把某一组切得太大或太小。这里有一个经验如果数据里存在极端离群值比如某个D-dimer直接飙到正常值的200倍best cutpoint会被这个点带偏。所以我在计算截断值前会先做一次描述统计把超过P99的值缩尾处理。截断值确定后赋值规则就非常清晰变量截断值参考低于截断值高于截断值纤维蛋白原3.9–4.2 g/L0分1分D-二聚体0.8–1.2 mg/L0分1分两项得分相加得到HFD 0、1、2分。这里要注意一个坑两个指标的截断值必须来自同一个训练集不能在测试集上寻找切点否则会产生乐观偏倚。如果你打算多中心验证也应该在第一个中心里定好阈值后面所有中心都用同一个阈值来复算HFD。2.3 模型验证的完整闭环从单因素到决策曲线把这个流程拆开看HFD研究本质上是一套标准的临床预测模型流水线我按实际操作顺序整理成了六个步骤第一步做基线描述。把训练集和验证集的人口学特征、临床病理特征、检验指标按HFD分层做组间比较连续变量用Kruskal-Wallis检验分类变量用卡方检验或Fisher精确检验这一步是为了证明HFD分层后各组基线均衡也就是风险分层确实能区分不同特征的患者。第二步是生存曲线分析。用Kaplan-Meier法绘制三条不同HFD得分组的生存曲线并用log-rank检验比较组间差异。预期结果必然是0分组的生存曲线显著高于1分组、2分组呈现清晰的剂量效应关系。这里有一条潜规则如果KM曲线交叉或P值不显著后面的多因素分析基本就不用做了先回头检查截断值或混杂因素。第三步是单因素Cox回归。把所有候选变量逐个放进Cox模型筛选出P值小于0.1或0.05的变量这一步的目的是缩小多因素模型的变量池避免把所有变量一锅炖进去造成过拟合。第四步是多因素Cox回归。把单因素里显著的变量同时放进模型采用向前或逐步法筛选独立预后因素。HFD在这个环节如果仍然保持显著并且风险比随着得分升高而递增这就是全文最重要的结论。第五步构建预测模型并评价区分度。用多因素Cox模型拟合训练集绘制列线图通过一致性指数C-index评价区分能力。一个可靠的模型通常要求训练集C-index在0.7以上验证集C-index差距不超过0.05否则提示过拟合或者变量选择有问题。最后是临床实用性评估。绘制校准曲线看预测生存概率和实际观察结果是否吻合再用决策曲线分析评估模型在不同阈值概率下的净获益证明模型确实比“全治疗”或“全不治疗”的策略更优。审稿人现在几乎必看DCA图没有这张图很难进一区。3. 复现全流程数据、代码、图表一步不落3.1 数据准备字段清单与数据清洗咱们这里说的复现不是让你一字不差去复制哈医大那篇原文的患者数据那既不现实也没必要。真正值得复现的是这套流程。你完全可以找一份自己科室的肝癌术后随访数据甚至公开数据库里带凝血指标和随访信息的队列也能练手。为了演示我用一份结构化后的模拟队列格式来说明字段组织方式。整理数据时最重要的一步是建立一份干净的、结构化的“训练集/验证集分列”表格。我强烈建议不要在一个Excel里搞多个sheet也不要在同一行后面加“训练/验证”备注这样后期会乱。正确做法是先把全数据集按7:3或按时间先后比如前2019年患者为训练集后为验证集划分好然后导出成两个独立的csv文件。需要整理的字段至少包括字段名类型说明ID字符患者唯一编号Age数值手术时年龄单位岁Sex二分类Male/FemaleBMI数值单位kg/m²LiverCirrhosis二分类有无肝硬化TNM_stage有序变量I/II/III期AFP数值对数转换后使用FIB数值术前血浆纤维蛋白原单位g/LD.dimer数值术前D-二聚体单位mg/LALT数值肝功能参考OS.time数值从手术到死亡或末次随访的月数OS二分类生存状态1表示事件发生数据清洗有几个容易忽视的细节。第一FIB和D-dimer的单位必须全国统一核对一遍不同实验室可能分别用g/L和mg/dL不换算直接合并会计算出荒谬的截断值。第二生存时间不能是0或负数如果手术当天死亡这种病例应该归入围手术期死亡并单独处理放进生存分析会直接报错或扭曲模型。第三AFP这类偏态非常严重的变量建议取log转换后再进模型否则变量尺度差异会让列线图的刻度非常难看。3.2 HFD计算与Cox回归的R语言实操环境准备方面我默认你已经装好了R和RStudio下面几个包是跑这套流程的刚需survival、survminer、rms、timeROC、dcurves没有装的话先执行install.packages()。第一步读入数据并计算截断值# 读取训练集 train - read.csv(train_hcc.csv, stringsAsFactors TRUE) test - read.csv(test_hcc.csv, stringsAsFactors TRUE) # FIB和D.dimer的截断值用训练集来定 library(survminer) cut_fib - surv_cutpoint(train, time OS.time, event OS, variables FIB) cut_dd - surv_cutpoint(train, time OS.time, event OS, variables D.dimer) print(cut_fib$cutpoint) # 显示最优切点 print(cut_dd$cutpoint)第二步根据截断值把连续变量转成二分类并计算HFD总分# 假设输出切点分别为fib_cut和dd_cut fib_cut - as.numeric(cut_fib$cutpoint$cutpoint) dd_cut - as.numeric(cut_dd$cutpoint$cutpoint) train$FIB_bin - ifelse(train$FIB fib_cut, 1, 0) train$DD_bin - ifelse(train$D.dimer dd_cut, 1, 0) train$HFD - train$FIB_bin train$DD_bin # 同样的阈值应用在测试集上 test$FIB_bin - ifelse(test$FIB fib_cut, 1, 0) test$DD_bin - ifelse(test$D.dimer dd_cut, 1, 0) test$HFD - test$FIB_bin test$DD_bin第三步单因素和多因素Cox回归重点看HFD的P值和风险比library(survival) # 以HFD为核心的单因素回归 cox_univ - coxph(Surv(OS.time, OS) ~ HFD, data train) summary(cox_univ) # 多因素回归调整主要临床变量 cox_multi - coxph(Surv(OS.time, OS) ~ HFD Age Sex TNM_stage AFP, data train) summary(cox_multi)我个人的习惯是先跑一个只有HFD的简模型确认HFD单独分组能力够强再逐步加协变量观察HFD的风险比有没有发生剧烈波动。如果加了某个变量后HFD从显著变成不显著要警惕这个变量是不是中介因素比如TNM分期本身就与凝血功能高度相关这时候文章结论就需要额外解释不能只丢一句“多因素分析保留HFD为独立因素”。3.3 生存曲线、列线图与DCA的绘制细节生存曲线的绘制是图表部分最容易出效果也最容易翻车的环节。用survfit函数拟合KM曲线推荐用ggsurvplot输出带风险表的图片km_fit - survfit(Surv(OS.time, OS) ~ HFD, data train) library(survminer) ggsurvplot(km_fit, data train, pval TRUE, risk.table TRUE, risk.table.col strata, palette c(#08519C, #D6604D, #01665E), xlab 随访时间月, ylab 总生存概率, legend.title HFD评分, legend.labs c(0分, 1分, 2分))这里有一个高分期刊的默认要求生存曲线一定要带风险表尤其是随访后期人越来越少风险表能让读者直观看到各个组仍然处于风险中的人数。如果你只画三条曲线没有风险表投稿时可能会被审稿人要求补图。列线图的绘制依赖rms包注意cph拟合参数中survTRUE和xTRUE, yTRUE必须打开否则后面计算生存概率函数会报错library(rms) dd - datadist(train) options(datadist dd) cph_fit - cph(Surv(OS.time, OS) ~ HFD Age Sex TNM_stage AFP, data train, x TRUE, y TRUE, surv TRUE, time.inc 36) # 定义36个月和60个月的生存概率函数 surv - Survival(cph_fit) nom - nomogram(cph_fit, fun list(function(x) surv(36, x), function(x) surv(60, x)), funlabel c(36个月生存概率, 60个月生存概率), lp FALSE) plot(nom)校准曲线可以直观反映预测概率和实际概率的一致程度推荐用rms自带的calibrate函数自助法重复次数B至少200次cal - calibrate(cph_fit, u 36, B 200) plot(cal, xlab 预测36个月生存概率, ylab 实际36个月生存概率)DCA图现在一键调用dcurves包就能画注意要同时画出模型和“全部干预”“全部不干预”两条参考线library(dcurves) dca_res - dca(Surv(OS.time, OS) ~ HFD Age Sex TNM_stage AFP, data train, time 36) plot(dca_res, smooth TRUE)画图时有一个非常实用的小技巧所有图尽量统一配色PDF输出时用CairoPDF嵌入字体不然投稿系统经常把中文标签渲染成方块。一区论文的图风格高度统一全部用的都是低饱和度色系不要一个图红绿蓝另一个图紫青黄这种细节往往决定了编辑对文章第一印象。4. 我在跑这套流程时踩过的坑4.1 六个高频问题排查速查表这类生存预测模型流程非常成熟但我在实际跑的时候几乎每次都能遇到至少一个奇葩问题整理成一个速查表放在下面问题表现可能原因解决办法surv_cutpoint报错“time must be numeric”生存时间读入了字符型用train$OS.time - as.numeric(train$OS.time)转换KM曲线三组P值不显著事件数太少或截断值偏离检查HFD 2分组人数是否少于总人数5%考虑换截断值minprop参数Cox回归中HFD的HR置信区间巨大变量存在完全分离某一组没有事件检查HFD2分组是否事件数过少必要时与1分组合并分析calibrate运行时间极长B值设得太大或变量数太多先用B200测试变量超过8个时建议先减少协变量列线图两侧刻度不对齐没有设置datadist检查是否执行options(datadist dd)且变量类型正确训练集C-index很高但验证集暴跌变量选择过拟合减少预测变量按EPV原则至少保证每个变量对应10个事件第六个问题是这类预测模型最普遍的坑我自己早期复现时吃过亏。三十个临床变量全部塞进多因素Cox做一个列线图训练集C指数0.86验证集直接掉到0.58红着脸被导师批了一顿。后来老老实实按EPV原则每个待选变量至少要有10个事件临床数据对应变量数量控制在5到7个模型才稳定下来。HFD这类复合指标比单指标的优势也体现在这里它用两个变量合成了一个得分进模型只占一行自变量空间信息量却不比两个原始变量少。4.2 审稿人爱挑的统计软肋怎么补复现流程能跑通只是第一步高分期刊投稿时审稿人对统计细节的挑剔才是真正的门槛。我整理了几个审稿人最爱问、也最容易被提问的问题以及对应的应对策略。第一截断值是否导致多重检验膨胀。你既做FIB的切点搜索又做D-dimer的切点搜索每个搜索本质上都做了多次假设检验审稿人可能会指出这是数据驱动的多重比较容易出现假阳性。我的建议是补充一个敏感性分析把连续型FIB和D-dimer也放进Cox模型证明趋势方向一致再用Hosmer-Lemeshow或校准图支持切点选择方案的合理性。第二缺少竞争风险分析。肝癌患者很多合并肝硬化相当比例患者的死亡其实由肝衰竭或消化道出血导致如果死因和肿瘤无关那么传统KM法会把非肿瘤死亡当作竞争事件处理。中老年队列、死亡原因复杂的瘤种建议补一个Fine-Gray竞争风险模型至少证明主要结论在竞争风险框架下依然成立。第三临床收益的表述不够量化。现在很多高分模型不仅报告C-index和AUC还会报告净重分类指数或临床影响曲线。你们如果只写“DCA提示有净获益”却没有说明在哪个阈值区间获益审稿人可能要求你再给一个临床决策阈值范围。比如在10%到40%的阈值概率范围内模型净获益高于“全部干预”这就是一个扎实的临床实用性结论。第四验证集的时间一致性。如果训练集和验证集是同一个中心不同年份的患者审稿人可能会质疑时间效应。如果两个数据集来自同一时间段可以补一句“时间跨度内治疗策略无重大变化”作为说明如果你能提前设计成不同中心的外部验证说服力最强哪怕样本量小一点也值得。5. 把HFD这套思路迁移到自己的课题上5.1 换指标、换瘤种、换数据库的通用路径认真把以上流程跑通之后你会发现HFD研究本质上提供了一套可迁移的“空壳”一个临床问题、一个复合评分、一套验证闭环。既然容器是通用的内容自然是可以替换的。最直接的替换维度是换指标组合。凝血方向可以换成纤维蛋白原与血小板COP分级、D-二聚体与中性粒细胞炎症方向可以用NLR与白蛋白构建预测指标或者把PAI、LMR这些已有指标重新验证营养方向可以整合前白蛋白、总胆固醇和淋巴细胞做成一个营养免疫评分。核心逻辑不变找两个或三个机制相关、临床易得、能互补的指标赋分合成然后套用同一套建模验证流程。第二个维度是换瘤种和人群。肝癌、食管癌、结直肠癌对凝血和炎症的依赖度比较高适合作为首选还可以往肺癌、胰腺癌、卵巢癌方向延伸甚至应用于自身免疫病的心血管预后预测。我建议优先选择事件率中等的疾病事件率太低比如甲状腺癌随访五年也死不了多少人统计效能会非常难看事件率太高也不行随访时间太短模型很容易被急性期因素干扰。第三个维度是换数据库。如果你所在的科室数据量不足可以借助公开数据库做外部验证MIMIC-IV里面有大量凝血指标和死亡率随访数据适合重症相关课题SEER数据库肿瘤类型广但缺少实验室检验指标适合做常规人口学和病理特征的预测模型TCGA数据库虽然测序数据多但临床随访信息有限且缺乏纤维蛋白原、D-二聚体这类蛋白指标。所以这套HFD思路最适合的场景还是自己医院的回顾性队列其次才是MIMIC这类检验指标齐全的重症数据库。5.2 从复现到超越的四个进阶方向复现一篇一区文章只能证明你掌握了一套流程真正要做出自己的增量还需要在原有基础上做升级。我这里给出四个实际操作中比较顺手的进阶方向。第一个方向是引入机器学习的变量筛选。传统的逐步Cox可能漏掉非线性关系你可以先用LASSO回归筛选特征把筛选出的变量再放进多因素Cox既避免共线性又能降维是目前很多高分预测模型的通用做法。LASSO的lambda值通过交叉验证确定指标的稳定性会明显好于纯逐步回归。第二个方向是把列线图升级成网页版计算器。列线图打印出来不方便在电脑上动态计算我见过很多团队把模型封装成一个RShiny应用或者一个在线评分页面医生输入数值就能直接得到预测概率。这个升级在临床推广上非常讨喜审稿人也愿意看到模型从“论文里的图”变成“临床能用的工具”。第三个方向是往时间维度扩展。普通列线图输出的是36个月和60个月两个固定时间点的概率但临床上更想要的是不同随访节点的连续预测。用动态列线图或时间依赖AUC展示模型在整个随访期内的表现会让模型的信息量高出一个维度。第四个方向是增加机制层面的佐证。如果条件允许可以在体外实验中观察纤维蛋白原对肿瘤细胞迁移侵袭的影响或者在组织芯片上检测凝血相关蛋白的表达。纯临床预测模型加一点基础实验机制验证文章档次可以再上一个台阶。当然不是所有临床团队都有实验条件至少可以在讨论部分深入解释肿瘤高凝状态与预后的分子通路。我个人在实际操作中的体会是做临床预测模型最忌贪大求全写作思路清晰比拿十几个变量硬建模有效得多。把HFD这条路线做扎实的关键就三点指标设计有机制依据、统计验证完整闭环、图表表达干净统一。做到这三点哪怕你的瘤种不如肝癌典型数据量不如大中心丰富也完全有底气去冲击高分期刊。建议你先用模拟数据或自己科室一个小队列把今天这套流程完整跑一遍跑通了再换指标、换瘤种这就是最稳妥的复现路径。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进