肿瘤突变负荷 TMB 计算¶
一句话说明¶
TMB(Tumor Mutational Burden)就是数一数肿瘤基因组里有多少个体细胞突变,突变越多意味着肿瘤产生的新抗原越多,免疫治疗(如 PD-1 抑制剂)可能越有效。
核心知识点¶
1. TMB 定义与单位¶
- 定义:肿瘤基因组每百万碱基(Mb)中体细胞非同义突变的数量
- 单位:mutations/Mb(突变数/兆碱基)
- 临床阈值:TMB-High 通常定义为 >=10 mut/Mb(FDA 批准的 Keytruda 适应症标准)
- 白话:TMB 就像一本书里的错别字密度,错别字越多说明这本书出错越厉害
2. 计算方法¶
- WES 计算:计入编码区非同义突变 / 靶区域总长度(~30-50 Mb)
- Panel 计算:计入 panel 覆盖区域的所有非同义突变 / panel 覆盖区域大小
- 关键细节:要排除已知驱动突变、胚系变异、同义突变(各实验室标准不完全统一)
3. TMB 与免疫治疗¶
- TMB-High 的肿瘤产生更多新抗原(neoantigen),更容易被免疫系统识别
- FDA 批准 TMB >= 10 mut/Mb 作为 pembrolizumab(Keytruda)的泛癌种生物标志物
- TMB 不是唯一的免疫治疗预测指标,需要结合 MSI、PD-L1 表达等
4. 不同平台的 TMB 计算差异¶
| 平台 | 覆盖区域 | 优点 | 缺点 |
|---|---|---|---|
| WGS | 全基因组 ~3 Gb | 最全面 | 成本高,计算复杂 |
| WES | 外显子 ~30-50 Mb | 金标准 | 成本中等 |
| Panel | 几百基因 ~1-2 Mb | 快速、临床常用 | Panel 太小会不准 |
实战代码¶
# === TMB 计算完整流程 ===
# 1. 先完成体细胞突变检测(接 319 的流程)
# 假设已有 filtered_somatic.vcf.gz
# 2. 提取 PASS 的非同义突变
bcftools view -f "PASS" \ # 只保留PASS变异
filtered_somatic.vcf.gz | \ # 输入VCF
bcftools query \ # 查询字段
-f '%CHROM\t%POS\t%REF\t%ALT\t%INFO/CSQ\n' | \ # 提取注释信息
grep -E "missense|nonsense|frameshift|splice" \ # 保留非同义变异
> nonsynonymous_variants.txt # 输出非同义变异列表
# 3. 计算靶区域大小(BED文件)
# WES 外显子靶区域
awk '{sum += $3 - $2} END {print sum / 1e6, "Mb"}' \
target_regions.bed # 计算BED覆盖总长度(Mb)
# 4. 计算 TMB
VARIANT_COUNT=$(wc -l < nonsynonymous_variants.txt) # 变异数
TARGET_SIZE=$(awk '{sum+=$3-$2} END {print sum/1e6}' target_regions.bed) # 区域大小Mb
TMB=$(echo "scale=2; $VARIANT_COUNT / $TARGET_SIZE" | bc) # TMB计算
echo "TMB = $TMB mutations/Mb" # 打印TMB值
# 用 Python 进行更精细的 TMB 计算
import cyvcf2 # 高效VCF解析库
import pandas as pd # 数据处理
def calculate_tmb(vcf_path, bed_path, min_vaf=0.05, min_depth=20):
"""
计算肿瘤突变负荷
vcf_path: 过滤后的体细胞突变VCF
bed_path: 靶区域BED文件
min_vaf: 最小VAF阈值
min_depth: 最小深度阈值
"""
# 计算靶区域大小
bed = pd.read_csv(bed_path, sep="\t", header=None, # 读取BED
names=["chrom", "start", "end"])
target_size_mb = (bed["end"] - bed["start"]).sum() / 1e6 # 总大小Mb
# 遍历VCF统计非同义突变
vcf = cyvcf2.VCF(vcf_path) # 打开VCF
mutation_count = 0 # 突变计数器
excluded_drivers = set() # 排除的已知驱动突变
for variant in vcf: # 遍历每个变异
if variant.FILTER is not None: # 跳过非PASS变异
continue
# 检查深度和VAF
tumor_dp = variant.format("DP")[0][0] # 肿瘤样本深度
tumor_ad = variant.format("AD")[0] # 等位基因深度
if tumor_dp < min_depth: # 深度不够跳过
continue
vaf = tumor_ad[1] / tumor_dp if tumor_dp > 0 else 0 # 计算VAF
if vaf < min_vaf: # VAF太低跳过
continue
# 检查是否为非同义突变(通过VEP注释)
info = variant.INFO # 获取INFO字段
csq = info.get("CSQ", "") # 获取VEP注释
if any(term in csq for term in # 检查功能影响
["missense", "nonsense", "frameshift",
"stop_gained", "splice_donor", "splice_acceptor"]):
mutation_count += 1 # 计数+1
# 计算TMB
tmb = mutation_count / target_size_mb # 突变数 / 区域大小
return {
"mutation_count": mutation_count, # 突变总数
"target_size_mb": round(target_size_mb, 2), # 靶区域大小
"tmb": round(tmb, 2), # TMB值
"tmb_high": tmb >= 10 # 是否TMB-High
}
# 使用示例
result = calculate_tmb("final_somatic.vcf.gz", "target.bed")
print(f"突变数: {result['mutation_count']}")
print(f"靶区域: {result['target_size_mb']} Mb")
print(f"TMB: {result['tmb']} mut/Mb")
print(f"TMB-High: {'是' if result['tmb_high'] else '否'}")
面试常问点¶
★ TMB 为什么能预测免疫治疗效果?¶
参考答案:TMB 高意味着肿瘤细胞积累了大量突变,这些突变会产生大量异常蛋白(新抗原/neoantigen),被 MHC 分子呈递到细胞表面,使免疫系统更容易识别肿瘤细胞为"异物"。免疫检查点抑制剂(如 PD-1 抑制剂)解除了免疫系统的"刹车",如果肿瘤有足够多的新抗原,解除刹车后免疫系统就能有效攻击肿瘤。TMB 低的肿瘤新抗原少,即使解除刹车也没什么可攻击的。
★ Panel 计算 TMB 准不准?¶
参考答案:关键看 Panel 的大小。研究表明 Panel 覆盖区域至少需要 1 Mb 以上才能与 WES 的 TMB 有较好的相关性。FoundationOne CDx(约 1.1 Mb)是 FDA 批准的 TMB 计算 Panel。Panel 太小(<0.5 Mb)时,TMB 估计的置信区间很大,容易误分类。另外不同 Panel 的计算标准不同(包含哪些突变类型、是否计入同义突变等),跨 Panel 比较需谨慎。
★ TMB 的局限性是什么?¶
参考答案:(1) TMB 不是万能的,一些 TMB-High 的肿瘤对免疫治疗无应答,反之亦然;(2) 不同平台/算法计算的 TMB 值不完全可比;(3) 阈值 10 mut/Mb 是基于 WES 数据定义的,不同癌种的最佳阈值可能不同;(4) TMB 应该和 MSI、PD-L1、基因表达等指标联合使用才更可靠。
速查卡片¶
| 问题 | 答案 |
|---|---|
| TMB 定义 | 体细胞非同义突变数/Mb |
| 临床阈值 | >= 10 mut/Mb (TMB-High) |
| FDA 批准用途 | Keytruda 泛癌种适应症 |
| WES 靶区域 | ~30-50 Mb |
| Panel 最小要求 | >1 Mb 才准 |
| 排除的变异 | 胚系变异、已知驱动突变 |
| 计入的变异 | 非同义突变(missense等) |
| TMB最高的癌种 | 黑色素瘤、肺癌、膀胱癌 |
| TMB最低的癌种 | 软组织肉瘤、甲状腺癌 |
| 联合指标 | MSI、PD-L1、GEP |