4、TMB阈值设定与临床分型归纳总结

TMB 阈值到底怎么定?说实话,这个问题我每年都要被问很多次。不同癌种、不同平台、不同检测试剂盒,出来的阈值可能完全不一样。你如果直接拿别人的cutoff用在自己数据上,很容易出问题。今天我把这些年踩过的坑、总结的经验,梳理清楚。

4.1 阈值设定的底层逻辑

TMB 阈值本质上是一个二分或三分界点。我们根据某个数值把患者分成“高 TMB”和“低 TMB”两组,然后看哪一组对免疫治疗更敏感。但问题来了:这个“高”到底多高才算高?

我个人习惯这样做:先拿到一个足够大的参考人群(至少几百例),计算他们的 TMB 分布。然后看免疫治疗临床试验中,响应患者的 TMB 集中在哪个范围。我曾在某 NSCLC 项目中遇到过,如果用全外显子组数据,建议 threshold 是 10 mut/Mb,但用 panel 数据做出来只有 8.5——因为 panel 覆盖区间的背景突变率不一样。

⚠️ 曾经有个教训:我直接用 TCGA 的阈值套在自家检测数据上,结果假阳性率偏高。后来才意识到,TCGA 是 WES 数据,而我们用的是 1.2 Mb 的 panel。所以别直接抄作业,要基于自己的数据重新校准。

现在主流做法有两种:

  • 基于百分位数:取参考人群 TMB 值的 85%~90% 分位数作为高 TMB cutoff。我曾见过有的中心用 75% 分位,结果把很多中等 TMB 的人也划进去了,反应率没明显提升。
  • 基于临床结局:找一组有免疫治疗应答数据的患者,用 ROC 曲线确定最佳 cutoff。这个更费事,但结果最可靠。
方法 适用场景 我遇到的坑
百分位数法 没有临床结局数据时先用 容易受离群值影响,比如某个样本超高频突变会把整体分布拉偏
ROC曲线法 有≥30例疗效数据时 样本量太小则曲线波动大,cutoff不稳定
固定经验值 特定癌种(如肺癌10 mut/Mb) 不同panel必须重新换算

4.2 不同癌种阈值差异实例

说到底,TMB 阈值没有“一招鲜”。我把常见癌种的典型阈值整理了一下——注意,这些数字只供参考。你自己用的时候要换算成 panel 对应值。

# 示例:基于最新文献和我的项目经验整理的阈值参考(WES当量)
癌种              TMB-H 阈值 (mut/Mb)    备注
非小细胞肺癌      10                     FDA 批准阈值,但实际有 8-15 波动
黑色素瘤          15                     部分研究用 20
尿路上皮癌        10                     和 NSCLC 接近
结直肠癌           5-8                    微卫星稳定型阈值更低
胃/食管腺癌        8-10                   亚洲人群可能偏高

你可能会问:为什么结直肠癌阈值这么低?说白了,MSI-H 的结直肠癌本来 TMB 就高,但 MSI 稳定型的 TMB 中位数只有 3~4。如果用 10 做 cutoff,几乎没人入选。我见过一个中心就是死守 10,结果他们的直肠癌队列里一个 TMB-H 都没有,报告根本写不出阳性结论。

这里有个技巧:如果你手头数据量不大,可以用公共数据库(TCGA、cBioPortal)算一下自己癌种的 TMB 分布,然后用分位数法初步拟定阈值。别上来就建队列做 ROC,太烧钱。

4.3 临床分型归纳——TMB 三分法

目前临床上最常用的是三分法:低 TMB、中 TMB、高 TMB。为什么分三档?因为中间那个“中 TMB”人群最让人头疼——他们可能有一部分对免疫有效,但比例不高。我习惯把这组叫“灰色地带”。

具体分型标准我建议参考以下原则(个人经验版):

  • 低 TMB:TMB 值低于目标癌种第 25 百分位数。这类患者使用免疫单药效果差,更适合化疗或靶向。
  • 中 TMB:第 25~85 百分位数。部分患者可能获益,尤其是联合治疗时。我没记错的话,CheckMate 227 事后分析显示,中 TMB 组双药免疫优于化疗。
  • 高 TMB:超过第 85 百分位数(或临床确定 cutoff)。这类患者是免疫治疗的最佳适合人群。
分型 百分位数范围(参考) 临床推荐
低 TMB < P25 不推荐单药免疫,考虑化疗/靶向
中 TMB P25 ~ P85 可考虑联合免疫,需结合 PD-L1 等标志
高 TMB > P85 推荐免疫单药或联合,疗效概率大

嗯,有一点要特别注意:同一患者在不同时间点检测,TMB 可能不一样。我曾遇到一个案例,活检时 TMB 9,半年后再测变成 12,刚好从“中”跨进“高”。这里面有克隆演化的问题,也有检测重复性的影响。所以分型最好基于最近一次样本。

4.4 工具与流程——实操中怎么算阈值

我做这块工作的标准流程大致是这样的:

  1. 收集参考人群 TMB 值:至少 200 例同一平台检测的数据。
  2. 去除异常样本:有 MSI-H 或 POLE 突变的样本会拉高均值,建议单独分析。我一开始没剔除 POLE 突变,结果 TMB 中位数虚高,差点误导了 cutoff。
  3. 计算百分位数:用 Python 的 numpy 做一下非常快。
  4. 可视化分布:画个直方图,看看有没有双峰。如果有,可能代表两种不同的基因组不稳定机制。
  5. 确定候选阈值:比如 P75, P85, P90。
  6. 如果有效应数据:用 ROC 曲线验证,保存逻辑回归结果。
import numpy as np
import matplotlib.pyplot as plt

# 假设 tmb_list 是参考人群的 TMB 值(mut/Mb)
tmb_arr = np.array(tmb_list)
percentiles = np.percentile(tmb_arr, [25, 50, 75, 85, 90, 95])
print("P25:", percentiles[0], "P50:", percentiles[1],
      "P75:", percentiles[2], "P85:", percentiles[3])

# 绘制直方图
plt.hist(tmb_arr, bins=30, edgecolor='k', alpha=0.7)
plt.axvline(x=percentiles[3], color='r', linestyle='--', label='P85')
plt.axvline(x=percentiles[4], color='orange', linestyle='--', label='P90')
plt.legend()
plt.xlabel('TMB (mut/Mb)')
plt.ylabel('Count')
plt.show()

这段代码我经常在项目初期快速跑一遍,看看数据大概长什么样。

小提示:如果参考人群中包含多癌种,别混在一起算百分位。我习惯按癌种分别统计,因为各癌种 TMB 分布差别太大了。

4.5 阈值设定与临床分型核心逻辑图

为了让整体思路更直观,我画了一张图。这张图把数据输入、校准过程、分型输出串起来了。

TMB阈值设定与临床分型流程 ① 参考人群TMB数据收集 ≥200例,同平台同癌种 ② 质量控制和异常排除 剔除MSI-H/POLE突变样本 ③ 计算分布与百分位数 P25 / P50 / P75 / P85 / P90 ④a 有临床结局数据 ROC曲线确定最佳cutoff ④b 无临床结局数据 使用P85或P90作为cutoff ⑤ 临床分型归纳 低TMB / 中TMB / 高TMB 注意:阈值需定期回看更新,尤其是检测平台升级或参考人群扩增时 对于跨癌种分析,建议独立设定阈值,不要做一个通用cutoff

4.6 最后几句实在话

阈值不是死的。你今年做的 cutoff,明年发现新药反应数据变了,就得跟着调。我见过一些团队一次性定好阈值后再也不动,结果临床反馈越来越差。我建议每半年或每次新增 50 例治疗后,重新校准一次。

还一点:报告里一定要写清楚阈值来源。比如“本报告参考本实验室最近 300 例同癌种检测数据 P85 分位数(XX mut/Mb)”。这样临床医生看到才知道怎么用。嗯,把这件事做规范了,后续分析会省掉很多争论。