跳转至

159_肿瘤微环境评估

一句话概述

肿瘤微环境(TME)评估通过ESTIMATE、TIMER2.0、MCPcounter和EPIC等计算工具从bulk RNA-seq数据中推断免疫细胞浸润、基质成分和肿瘤纯度,为免疫治疗响应预测和预后分层提供关键信息。


核心知识点总览

知识点说明
ESTIMATE估计肿瘤纯度、免疫评分和基质评分的ssGSEA方法
TIMER2.0综合免疫浸润分析平台,集成多种反卷积方法
MCPcounter基于标记基因的免疫/基质细胞丰度估计
EPIC从bulk RNA-seq估计细胞类型比例(含未识别细胞)
xCell基于ssGSEA的64种细胞类型评分
免疫评分(Immunoscore)量化肿瘤免疫浸润程度的综合指标
方法对比各方法的输入要求、输出含义和适用场景差异

各步骤详解

第一步:TME评估的意义和方法分类

白话解释: 肿瘤不是只有癌细胞——它像一个"微型生态系统",里面有免疫细胞(T细胞、巨噬细胞等)、基质细胞(成纤维细胞、内皮细胞)和细胞外基质。这个"生态系统"的组成决定了肿瘤是"热"(免疫活跃,对免疫治疗响应好)还是"冷"(免疫沉寂,治疗效果差)。

方法分类: | 类别 | 方法 | 原理 | 输出 | |------|------|------|------| | 基因集评分 | ESTIMATE, xCell | ssGSEA/enrichment | 评分值(相对量) | | 标记基因 | MCPcounter | 标记基因平均表达 | 丰度评分(相对量) | | 反卷积 | EPIC, quanTIseq, CIBERSORT | 线性模型求解 | 比例(0-1之和=1) | | 混合方法 | TIMER2.0 | 集成多种方法 | 多种输出 |


第二步:ESTIMATE分析

代码示例:

# 安装
# install.packages("estimate")
# 或从Bioconductor/GitHub
library(estimate)

# 1. 输入: 基因表达矩阵 (基因×样本, 行名为基因symbol)
# ESTIMATE需要特定格式的GCT文件
write.table(expression_matrix, "expression.txt", sep="\t", quote=FALSE)

# 使用ESTIMATE函数
# 过滤共有基因
filterCommonGenes(
  input.f = "expression.txt",
  output.f = "expression_filtered.gct",
  id = "GeneSymbol"
)

# 计算三个评分
estimateScore(
  input.ds = "expression_filtered.gct",
  output.ds = "estimate_scores.gct",
  platform = "illumina"  # "affymetrix" 或 "illumina"
)

# 读取结果
scores <- read.delim("estimate_scores.gct", skip = 2)
# 包含: StromalScore, ImmuneScore, ESTIMATEScore, TumorPurity

# 可视化
library(ggplot2)
scores_long <- tidyr::pivot_longer(scores, cols = c("StromalScore", "ImmuneScore"),
                                    names_to = "Score_Type", values_to = "Score")
ggplot(scores_long, aes(x = Score_Type, y = Score)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "ESTIMATE Scores")

# 按肿瘤纯度分层
scores$PurityGroup <- ifelse(scores$TumorPurity > median(scores$TumorPurity),
                              "High_Purity", "Low_Purity")


第三步:TIMER2.0综合分析

代码示例:

# TIMER2.0在线平台: http://timer.cistrome.org/
# 或使用immunedeconv R包调用

# 安装immunedeconv (统一接口)
# devtools::install_github("omnideconv/immunedeconv")
library(immunedeconv)

# 输入: TPM表达矩阵 (基因symbol × 样本)
expr_tpm <- as.matrix(expression_tpm)

# === TIMER方法 ===
timer_result <- deconvolute(expr_tpm, method = "timer",
                             indications = rep("blca", ncol(expr_tpm)))  # TCGA肿瘤类型缩写

# === quanTIseq ===
quantiseq_result <- deconvolute(expr_tpm, method = "quantiseq",
                                 tumor = TRUE)

# === CIBERSORT (需要注册token) ===
# cibersort_result <- deconvolute_cibersort(expr_tpm, 
#                                            arrays = FALSE)

# === EPIC ===
epic_result <- deconvolute(expr_tpm, method = "epic")

# === 综合多种方法 ===
methods <- c("timer", "quantiseq", "mcp_counter", "epic", "xcell")
all_results <- list()
for (m in methods) {
  tryCatch({
    if (m == "timer") {
      all_results[[m]] <- deconvolute(expr_tpm, method = m,
                                       indications = rep("blca", ncol(expr_tpm)))
    } else {
      all_results[[m]] <- deconvolute(expr_tpm, method = m)
    }
  }, error = function(e) cat(m, "failed:", e$message, "\n"))
}

# 合并T细胞估计并比较
library(ggplot2)
tcell_comparison <- data.frame(
  Sample = colnames(expr_tpm),
  EPIC_Tcell = as.numeric(all_results$epic["T cell CD4+", ]),
  quanTIseq_Tcell = as.numeric(all_results$quantiseq["T cell CD4+", ]),
  MCP_Tcell = as.numeric(all_results$mcp_counter["T cell", ])
)


第四步:MCPcounter分析

代码示例:

# 安装
# devtools::install_github("ebecht/MCPcounter", ref="master", subdir="Source")
library(MCPcounter)

# MCPcounter估计10种细胞类型的丰度
# 输入: 基因表达矩阵(基因×样本)
mcp_result <- MCPcounter.estimate(
  expression = expr_tpm,
  featuresType = "HUGO_symbols"  # 或 "ENSEMBL_ID"
)

# 输出: 10种细胞类型 × N样本的评分矩阵
# T cells, CD8 T cells, Cytotoxic lymphocytes, B lineage
# NK cells, Monocytic lineage, Myeloid dendritic cells
# Neutrophils, Endothelial cells, Fibroblasts
print(rownames(mcp_result))

# 热图可视化
library(pheatmap)
pheatmap(mcp_result,
         scale = "row",
         clustering_method = "ward.D2",
         annotation_col = sample_annotation,
         color = colorRampPalette(c("blue", "white", "red"))(100),
         main = "MCPcounter Cell Type Scores")

# 与临床变量关联分析
library(survival)
library(survminer)

# 以CD8 T细胞为例
clinical$CD8_score <- mcp_result["CD8 T cells", rownames(clinical)]
clinical$CD8_group <- ifelse(clinical$CD8_score > median(clinical$CD8_score),
                              "High", "Low")

fit <- survfit(Surv(OS_time, OS_event) ~ CD8_group, data = clinical)
ggsurvplot(fit, data = clinical, pval = TRUE, risk.table = TRUE,
           title = "OS by CD8 T cell Infiltration")


第五步:EPIC反卷积

代码示例:

# 安装: devtools::install_github("GfellerLab/EPIC")
library(EPIC)

# EPIC估计细胞比例(和为1),包含"otherCells"(未识别成分)
epic_result <- EPIC(
  bulk = expr_tpm,           # TPM矩阵
  reference = NULL,          # 使用默认参考(TRef/BRef)
  mRNA_cell = NULL,          # 默认mRNA/cell估计
  sigGenes = NULL            # 默认签名基因
)

# 结果包含:
# $cellFractions: 细胞比例矩阵
# $fit.gof: 拟合优度
cell_fractions <- epic_result$cellFractions
print(head(cell_fractions))
# 细胞类型: B cells, CAFs, CD4+ T cells, CD8+ T cells, 
#           Endothelial, Macrophages, NK cells, otherCells

# 堆叠柱状图
library(tidyr)
library(ggplot2)
fractions_df <- as.data.frame(cell_fractions)
fractions_df$Sample <- rownames(fractions_df)
fractions_long <- pivot_longer(fractions_df, -Sample, 
                               names_to = "CellType", values_to = "Fraction")

ggplot(fractions_long, aes(x = Sample, y = Fraction, fill = CellType)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 6)) +
  labs(title = "EPIC Cell Type Fractions") +
  scale_fill_brewer(palette = "Set3")


第六步:多方法整合与临床关联

代码示例:

# === 整合多种方法的免疫评分 ===
# 标准化各方法的评分到0-1范围
scale_01 <- function(x) (x - min(x, na.rm=T)) / (max(x, na.rm=T) - min(x, na.rm=T))

immune_scores <- data.frame(
  ESTIMATE_immune = scale_01(estimate_scores$ImmuneScore),
  MCP_CD8 = scale_01(mcp_result["CD8 T cells", ]),
  EPIC_CD8 = scale_01(epic_result$cellFractions[, "CD8+ T cells"]),
  row.names = colnames(expr_tpm)
)

# 相关性检验
cor_matrix <- cor(immune_scores, use = "complete.obs", method = "spearman")
print(round(cor_matrix, 3))

# === 免疫亚型分类 ===
# 基于免疫浸润模式将肿瘤分为免疫亚型
library(ConsensusClusterPlus)

# 使用多种免疫评分做聚类
immune_matrix <- t(scale(t(rbind(mcp_result, estimate_immune = estimate_scores$ImmuneScore))))

cc_results <- ConsensusClusterPlus(
  d = immune_matrix,
  maxK = 6,
  reps = 100,
  pItem = 0.8,
  clusterAlg = "hc",
  distance = "pearson",
  seed = 42
)

# 选择最优K
immune_subtypes <- cc_results[[3]]$consensusClass  # 假设K=3最优

# === 与免疫治疗响应关联 ===
# 比较不同免疫亚型的PD-L1表达和TMB
boxplot_data <- data.frame(
  Subtype = factor(immune_subtypes),
  PDL1 = expr_tpm["CD274", ],  # PD-L1 = CD274
  TMB = sample_tmb
)

ggplot(boxplot_data, aes(x = Subtype, y = PDL1, fill = Subtype)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "PD-L1 Expression by Immune Subtype")


实战命令

# === R包安装 ===
Rscript -e '
install.packages("estimate")
devtools::install_github("omnideconv/immunedeconv")
devtools::install_github("ebecht/MCPcounter", ref="master", subdir="Source")
devtools::install_github("GfellerLab/EPIC")
BiocManager::install("GSVA")
'

# === TIMER2.0在线分析 ===
# 访问 http://timer.cistrome.org/
# 上传TPM表达矩阵
# 选择肿瘤类型和分析模块

# === 批量分析脚本 ===
Rscript tme_analysis.R --expr expression_tpm.csv \
  --clinical clinical.csv \
  --methods "ESTIMATE,MCPcounter,EPIC,quanTIseq" \
  --output results/

面试常问点

Q1:ESTIMATE评分的含义是什么?

A: ESTIMATE通过ssGSEA方法计算三个评分:(1) StromalScore: 基于141个基质相关基因的富集程度,反映肿瘤样本中基质细胞含量;(2) ImmuneScore: 基于141个免疫相关基因的富集程度,反映免疫细胞浸润水平;(3) ESTIMATEScore: 两者之和,用于推算肿瘤纯度(TumorPurity = cos(0.6049872018 + 0.0001467884 * ESTIMATEScore))。注意这些是相对评分,不是绝对细胞比例。

Q2:MCPcounter和CIBERSORT的本质区别是什么?

A: MCPcounter使用标记基因的平均表达来估计细胞"丰度"(abundance score)——输出是任意单位的评分,样本间可比但不代表比例。CIBERSORT使用反卷积(ν-SVR)估计细胞"比例"(proportion)——输出各细胞类型的相对比例(和为1)。关键区别:MCPcounter的评分不受其他细胞类型影响(独立估计);CIBERSORT的比例是相互依赖的(组成性约束)。

Q3:为什么不同方法对同一样本的免疫评估结果可能不一致?

A: (1) 定义不同: 各方法定义的细胞类型粒度不同(如T细胞vs CD4+ T细胞);(2) 输出含义不同: 评分(MCPcounter) vs 比例(EPIC) vs 富集(xCell)不可直接比较;(3) 参考谱差异: 使用的标记基因集/签名矩阵不同;(4) 假设不同: CIBERSORT假设所有细胞类型已知,EPIC允许未知成分。建议使用多种方法,取一致性高的结论。

Q4:TME评估在免疫治疗中有哪些临床应用?

A: (1) 免疫治疗响应预测: 高CD8 T细胞浸润通常预测抗PD-1/PD-L1治疗响应好;(2) 免疫亚型分类: 区分"热肿瘤"(免疫浸润高)和"冷肿瘤"(免疫排斥/沙漠);(3) 联合治疗策略: 高M2巨噬细胞提示可能需要联合抗CSF1R治疗;(4) 预后分层: Immunoscore已被证明在结直肠癌中优于传统TNM分期。

Q5:如何选择合适的TME评估方法?

A: 取决于研究目的:(1) 需要肿瘤纯度→ESTIMATE;(2) 需要细胞类型比例→EPIC或quanTIseq;(3) 需要详细免疫亚群→CIBERSORT(LM22有22种)或xCell(64种);(4) 需要绝对丰度→MCPcounter;(5) 多方法整合→immunedeconv包统一调用。如果条件允许,建议运行3-4种方法并报告一致性结果。


易错点

1. 输入数据格式错误

错误: 用counts数据输入需要TPM的方法(如EPIC)。 正确做法: 检查每个方法的输入要求:ESTIMATE可用芯片或RNA-seq(log2);MCPcounter/EPIC需要TPM或FPKM;CIBERSORT需要TPM(非log)。

2. 混淆"评分"和"比例"

错误: 将MCPcounter的评分值直接当作细胞比例(如"CD8 T细胞占20%")。 正确做法: MCPcounter输出是丰度评分(无单位),只能做组间比较(A组CD8评分高于B组),不代表绝对比例。只有EPIC、quanTIseq等反卷积方法输出比例。

3. 忽略肿瘤纯度的影响

错误: 不考虑肿瘤纯度就比较不同样本的免疫评分。 正确做法: 高纯度肿瘤样本的免疫评分自然低(免疫细胞少)。应在比较时校正纯度,或使用绝对量估计方法。

4. 对微阵列和RNA-seq数据不区分

错误: 将微阵列数据的参数用于RNA-seq分析。 正确做法: 不同平台的数据分布不同。ESTIMATE有platform参数;CIBERSORT有QN选项(微阵列用TRUE,RNA-seq用FALSE)。

5. 过度解读单一方法结果

错误: 仅凭一种方法的结果下结论。 正确做法: 至少使用2-3种方法交叉验证。如果多种方法一致地显示CD8 T细胞浸润高,结论更可靠。


补充知识

方法选择速查表

需求推荐方法
肿瘤纯度估计ESTIMATE, ABSOLUTE
免疫/基质总体评分ESTIMATE
详细免疫细胞亚型(22种)CIBERSORTx
细胞类型比例(含未知成分)EPIC
多种细胞丰度评分MCPcounter
最多细胞类型(64种)xCell
多方法一站式TIMER2.0 / immunedeconv

TCGA TME资源

  • TIMER2.0: 预计算的所有TCGA肿瘤类型的免疫浸润数据
  • TCIA(The Cancer Immunome Atlas): TCGA免疫表型数据
  • TIDE: 免疫治疗响应预测平台

与其他教程的联系

  • 148_表达矩阵反卷积 → 反卷积方法的技术细节
  • 166_DNA损伤修复通路 → HRD与免疫微环境的关系
  • 100_免疫浸润分析 → 更详细的免疫浸润分析教程