☰
免疫浸润分析实战:用IOBR从表达矩阵到预后模型
2026/10/18 2:53:35 网站建设 项目流程

简介:IOBR免疫浸润分析R包提供了完整的源代码、示例数据与使用文档,面向肿瘤微环境解析、免疫浸润评估和生物信息学分析场景,适用于肿瘤免疫、单细胞测序数据挖掘方向的研究者,也适合R语言初学者上手实践。资源共18个文件,核心为7个R脚本,覆盖数据加载、批量运行CIBERSORT、EPIC、quanTIseq等免疫浸润分析、签名打分及热图可视化;3个RData文件内置示例表达谱、样本信息和批次校正结果,便于直接复现流程;另有CSV结果表、PNG示意图和README文档辅助理解。压缩包约9.53MB,轻量且目录清晰。目前已有206人学习浏览。IOBR集成了8种免疫浸润方法、264个涵盖肿瘤微环境、代谢、m6A等领域的基因集签名,支持PCA、z-score、ssGSEA三种打分策略,还能完成单细胞配体-受体网络分析和微环境聚类分群,帮助研究者从原始数据到结果展示一气呵成,既适合作教学案例,也可直接用于课题预实验,有效节省算法搭建与调参时间。

1. 为什么我会选择IOBR做免疫浸润分析

1.1 免疫浸润分析是什么,为什么要做

肿瘤微环境(Tumor Microenvironment, TME)不是肿瘤细胞的独角戏,里面挤着各种免疫细胞、基质细胞、成纤维细胞。这些细胞和肿瘤细胞之间的“对话”,直接决定了免疫治疗有没有效、患者预后好不好。免疫浸润分析,学术点说就是通过转录组表达数据反推每个样本里有哪些免疫细胞、比例大概是多少。临床上做的所谓“冷肿瘤”和“热肿瘤”,判断依据就来源于这种分析。

这几年做肿瘤生信的人越来越多,免疫浸润分析几乎成了转录组数据挖掘的标配步骤。无论是GEO下载的芯片数据、TCGA的RNA-seq数据,还是自己课题组跑的测序结果,拿到表达矩阵后的第一件事往往就是跑一遍免疫浸润,看看不同分组之间免疫细胞组分有没有差异。这个结果不仅能回答“这个肿瘤是不是免疫原性比较强”,还能为后续找biomarker、建预后模型、预测免疫治疗响应提供基础。

早些年做免疫浸润分析很痛苦。CIBERSORT需要单独处理LM22签名矩阵,TIMER要去网站跑完再手动下载结果,xCell的R包更新又慢,不同算法出来的人名还经常对不上。我当时第一次做这个分析,光是把五种算法结果整合到一张热图里,就手工折腾了两天。所以当我第一次看到IOBR这个R包时,确实有“相见恨晚”的感觉。

1.2 IOBR相比单工具的核心优势在哪

IOBR全称Immuno-Oncology Biomarker Resource,是重庆医科大学某团队开发的一个专注于肿瘤免疫微环境分析和biomarker挖掘的R包。它最大的价值不是自己发明了一个新算法,而是把主流的免疫浸润反卷积算法整合到了一套统一框架里。内置了CIBERSORT、CIBERSORTx、TIMER、EPIC、MCPcounter、xCell、ssGSEA、ESTIMATE等十多种常用方法,一个函数就能全部跑完。

用我自己的话说,这就是把“各家算法散装工具”做成了一个可复现的流水线。对科研人员来说有三个直接好处:第一,不用再记每个工具独立的输入输出格式,统一塞进去一个表达矩阵就完事;第二,结果名统一,方便后续做整合分析;第三,所有参数都透明可调,不会出现“不知道这个结果是怎么算出来”的黑箱感。

2. 环境准备与R包安装

2.1 基础环境要求

IOBR本身依赖了不少R包,所以安装前先确认R版本。实测下来R 4.1以上都比较稳,R 4.3也正常。操作系统方面Windows、macOS、Linux都能跑,但强烈建议在Linux服务器上跑,尤其是样本量上百的转录组数据,跑多个算法时内存消耗不小。

还要装好Rtools(Windows环境),因为IOBR在安装过程中会从GitHub拉取代码并编译,没有Rtools会直接报错。这个点在Windows上踩的人特别多,装完R之后第一件事就是把Rtools对应的版本老老实实装好。

2.2 安装IOBR的完整流程

IOBR可以通过GitHub安装,推荐使用devtools或remotes。先安装依赖,再装主包:

# 安装BiocManager核心依赖 if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install(c("limma", "DESeq2", "edgeR", "clusterProfiler")) # 安装IOBR依赖 install.packages(c("devtools", "glmnet", "survival", "survminer", "pheatmap", "ggplot2")) # 从GitHub安装IOBR devtools::install_github("IOBR/IOBR") library(IOBR)

装完之后建议跑一下?IOBR看一眼帮助文档能正常加载。如果安装过程中出现类似“there is no package called 'xxx'”的报错,缺什么就先装什么,这是最常规的解决方式。

2.3 安装踩坑记录

有一个比较隐蔽的坑是Github源包版本更新频繁,旧版本和新版本在函数名上会有出入。比如旧版本的deconvo_tme()在个别参数命名上和新版不一样,直接抄网上的老教程代码会跑不通。我的习惯是装完后跑一下packageVersion("IOBR")记下版本号,再对着官方GitHub README里的参数做核对,别盲目照搬别人的代码。

另外Windows用户如果在安装时遇到编译失败,常见原因是Rtools版本没对齐。装R 4.3就配Rtools43,装R 4.2就配Rtools42,版本错位是最常踩的坑。

3. 免疫浸润分析实操:从表达矩阵到细胞比例

3.1 数据准备与格式规范

在跑IOBR之前,表达矩阵的整理是重中之重。我见过太多人在这里栽跟头——矩阵没整理好,后面分析出来的结果全是错的,浪费大量时间。IOBR默认接受的表达矩阵需要满足两个条件:基因名是Symbol格式(如TP53),行是基因,列是样本。

如果你手上的是Ensembl ID或者Entrez ID,用anno_hugene21()这类内置注释函数做转换就行。IOBR内置了常用平台的注释文件,这个设计挺贴心,省去了一堆gene mapping的麻烦。需要注意重复基因名处理,多个探针对同一个Symbol时,建议用aggregate()取均值或最大值,尽量避免重复行。

临床信息方面,至少需要准备样本ID、分组信息(比如肿瘤组vs对照组)和生存数据(生存时间+生存事件)。后续Lasso和Cox建模都要用到这些字段,建议从一开始就整理成一个数据框,不要等到建模那一步才手忙脚乱去找临床信息。

3.2 一键运行多算法反卷积

数据准备好之后,IOBR最核心的函数就是deconvo_tme()。它的用法非常直接,指定表达矩阵和要运行的算法向量,就能一次性输出结果:

# 加载示例数据(IOBR自带) data("im_data_6", package = "IOBR") # 运行多种反卷积算法 decon_res <- deconvo_tme(eset = im_data_6, method = c("cibersort", "timer", "epic", "mcpcounter", "xcell"), pArray = 0.01, perm = 1000) # 查看结果结构 str(decon_res)

我习惯把perm(置换次数)设成1000,虽然运行时间会变长,但结果的稳定性比默认值更好。做正式发表的研究时,置换次数太小时P值算出来不够稳健,审稿人问到不好回答。另外pArray这个参数控制在0.01水平上的统计过滤,可以保留所有输出结果便于后续分析,不必过分追求极小的P值。

跑完后你会得到一个列表,每个元素对应一种算法的输出。以CIBERSORT结果为例,每一行是一个样本,后面的列是各免疫细胞的比例,最后一列是P值。多个算法的输出整合到一起也比较方便,do.call(cbind, decon_res)就能拼一个大宽表出来,方便后续做相关性或差异分析。

3.3 结果解读:算法之间怎么对齐

不同算法的输出细胞类型命名并不一致。比如EPIC输出的叫“Macrophage”,CIBERSORT输出的是M0、M1、M2三种巨噬细胞亚群,xCell的输出里又有“Macrophages M1”“Macrophages M2”。第一次做整合分析的同学往往会在这里宕机。

我在实际操作中的做法是,先跑单个算法看输出列名,再用IOBR内置的cell_type_anno或手动建立一个统一命名的映射字典,把生物学上等价的细胞类型归到同一名称下再合并。比如“T cells CD8”和“CD8+ T cells”本质上是一个细胞群,后面做热图或差异性分析时合并成一个变量更科学。这步虽然有点脏活累活,但直接决定了后续图表的可读性。

4. 进阶:Lasso特征筛选与预后模型构建

4.1 为什么要用Lasso

免疫浸润分析本身跑完只是起点,大多数情况下你的目标是找到跟预后相关的免疫特征,构建一个预后模型,或者筛选出潜在的biomarker。问题在于免疫细胞类型有几十种,加上各种免疫相关基因,特征维度很高,直接扔进Cox回归必然会过拟合——你会在训练集里得到“完美”的模型,但拿到验证集上一测就崩。

Lasso回归天然适合干这个事。它通过L1正则化让大部分特征的系数压缩到0,只保留少数最有判别力的特征,既能降维又能防过拟合。现实类比一下:你手上有50个嫌疑特征,Lasso帮你先“面试”一遍,最后只留下5个真正有用的进入“复试”。这比你自己一个个试要客观得多,也省时间。

4.2 Lasso特征筛选实操

在拿到IOBR的细胞浸润比例结果之后,我通常会结合基因表达层面一起做筛选。以下是基于glmnet包做Lasso-Cox的完整代码:

library(glmnet) library(survival) # 假设decon_res是IOBR输出的矩阵,dat_clin是临床信息 # 确保样本对齐 common_samps <- intersect(rownames(decon_res), dat_clin$sample_id) dat <- decon_res[common_samps, ] clin <- dat_clin[match(common_samps, dat_clin$sample_id), ] # 构建训练矩阵 x_mat <- as.matrix(dat) y_surv <- Surv(time = clin$OS.time, event = clin$OS.event) # 设置种子保证可复现 set.seed(2024) # 10折交叉验证 cv_fit <- cv.glmnet(x_mat, y_surv, family = "cox", nfolds = 10) # 打印最优lambda print(cv_fit$lambda.min) print(cv_fit$lambda.1se) # 提取系数非零的特征 coef_fit <- coef(cv_fit, s = cv_fit$lambda.min) selected_genes <- rownames(coef_fit)[which(coef_fit != 0)] print(selected_genes) # 计算每个样本的risk score risk_score <- predict(cv_fit, newx = x_mat, s = cv_fit$lambda.min, type = "link")

选择lambda.min还是lambda.1se要看你具体情况。从我的实操经验看,lambda.min会保留更多特征,适合特征数量本身不算太多、希望模型解释性好一点的场景;lambda.1se更严格,筛出来的特征更少,模型更简洁,但可能丢掉一些边缘有效的变量。如果后续打算做临床转化方向的模型,我倾向使用lambda.min,给后面的多因素模型留出变量候选空间。

4.3 多因素Cox模型的落地

Lasso筛完特征后,一般还要用多因素Cox回归来构建最终的预后模型,评估每个特征是否独立影响预后。这里有个重要操作细节:Lasso缩出来的系数在解释性上不如传统Cox的HR值直观,所以大多数论文的处理方式是把Lasso筛出来的变量再带入coxph()跑一遍,输出HR和95%置信区间。

library(survival) library(survminer) # 用Lasso筛出的特征构建数据 final_dat <- data.frame(decon_res[, selected_genes], clin) colnames(final_dat)[1:length(selected_genes)] <- selected_genes # 多因素Cox cox_model <- coxph(Surv(OS.time, OS.event) ~ ., data = final_dat) summary(cox_model) # 计算每个样本的risk score final_dat$riskScore <- predict(cox_model, type = "lp") # 按中位值分组 final_dat$riskGroup <- ifelse(final_dat$riskScore > median(final_dat$riskScore), "High", "Low")

到这一步,你就有了一个可以画生存曲线、可以做独立预后因素森林图、甚至可以在验证集里验证的完整预后模型。流程下来一气呵成,这就是IOBR整合框架的便利之处——从头到尾不需要切到别的工具里去倒腾数据。

5. 可视化与发表级图表输出

5.1 热图:免疫浸润全景一图看尽

热图是免疫浸润分析最常用的展示方式之一,把样本按分组排列,展示各免疫细胞的比例差异。我习惯用pheatmap,IOBR跑完的结果直接喂给pheatmap就能出图:

library(pheatmap) # 只选免疫细胞比例列 cell_matrix <- as.matrix(deon_res[, grep("_CIBERSORT|_EPIC|_MCP_counter", colnames(decon_res))]) # 简单重命名列方便展示 colnames(cell_matrix) <- gsub("_.*", "", colnames(cell_matrix)) # 按分组做注释 annotation_col <- data.frame(group = clin$group) rownames(annotation_col) <- rownames(cell_matrix) pheatmap(cell_matrix, annotation_col = annotation_col, scale = "row", cluster_cols = FALSE, fontsize_row = 8, fontsize_col = 8, color = colorRampPalette(c("#4472C4", "white", "#ED7D31"))(100))

需要提醒的是scale = "row"会让每行基因的表达量标准化到均值为0,这样更能反映相对丰度的高低,但也会丢失绝对比例的差异信息。如果细胞类型之间比例差异本身就很大,我建议再做一版不归一化的热图对比一下,免得审稿人问“为什么T细胞比例这么低的样本在图里反而是红的”。

5.2 生存曲线与森林图

预后模型建好之后,生存曲线是最高频的可视化需求。用survminer画K-M曲线非常成熟,只需一行ggsurvplot():

fit_surv <- survfit(Surv(OS.time, OS.event) ~ riskGroup, data = final_dat) ggsurvplot(fit_surv, data = final_dat, pval = TRUE, risk.table = TRUE, palette = c("#E64B35", "#4DBBD5"), xlab = "Time (months)", ylab = "Overall Survival")

画森林图可以用forestplot包,展示多因素Cox中每个变量的HR值和置信区间。这个图在肿瘤生信论文里出现频率极高,重点突出哪些因素是独立预后因素。个人建议在图中同时标注P值和HR,让读者一眼就能抓到关键信息。

6. 常见问题与排查指南

6.1 常见报错速查表

我把自己和身边朋友遇到的高频问题整理了一份速查表,按出现频率排序:

问题现象解决方案
安装失败installation of package had non-zero exit status优先补装缺失依赖;检查Rtools版本是否匹配R版本
deconvo_tme报错object 'xxx' not found升级IOBR到最新版;对比GitHub README更新参数名
样本不对齐临床信息和表达矩阵的样本ID顺序不一致用intersect()取交集后再match()对齐
基因名重复aggregate后仍有重复行导致报错选最大均值或最大表达量去重,避免随意剔除
内存不足RStudio直接卡死或报cannot allocate vector of size换用服务器;只保留需要的样本和基因;关掉无关窗口释放内存
置换检验过慢perm=1000运行时间太长先用perm=100跑通流程,确认无报错后再设1000过夜跑

6.2 数据质量与生物学解读的坑

先说几个数据层面的坑。芯片数据和RNA-seq数据不要混在一起跑反卷积,不同平台的技术差异会直接影响结果,除非你做了一板一眼的批次校正,否则尽量别混。样本量太少(比如每组只有三五个样本)时,反卷积结果特别不稳定,我自己跑过一组只有4个肿瘤样本的数据,CIBERSORT和EPIC给出来的细胞比例完全对不上,这时候不要强行下生物学结论,优先考虑增加样本或者换用更稳健的ssGSEA打分。

再说生物学解读。免疫浸润比例本质上是相对丰度,不是绝对数量。CIBERSORT输出所有细胞比例之和是100%,这意味着T细胞比例升高可能只是“其他人少导致的相对升高”,不代表T细胞绝对数量增加了。解读的时候要有这个概念,别一看到CD8+ T细胞比例高了就写“说明免疫活性增强”,还要结合临床、病理、其他marker表达交叉验证。

另外不同算法之间存在系统性偏差,这是正常现象。我跑过一个数据集,CIBERSORT说巨噬细胞M2是主要浸润群,xCell却提示M1更高。这时候最重要的是看算法本身的分辨能力,以及签名矩阵在不同癌种中的适用性。MCPcounter对成纤维细胞和内皮细胞识别较灵敏,EPIC对肿瘤纯度的处理更细致,xCell在免疫细胞亚群覆盖度上更广。没有哪个算法是绝对的金标准,审稿人更接受的是“用多种算法交叉验证,结果趋势一致”。

还有一个特别常见的坑:deconvo_tme()跑CIBERSORT时,如果表达矩阵已经做了z-score标准化,会导致结果全部异常。CIBERSORT输入要求是非负的原始表达量或芯片荧光强度值,z-score之后有大量负值,直接跑会让算法内部取对数时产生NaN。我自己有一次就是这个原因卡了半天,排查下来发现是上游预处理代码里顺手做了标准化。建议在跑IOBR之前,确认输入矩阵没有经过log2之外的复杂变换。

关于免疫治疗相关的分析,IOBR也内置了signature_score()可以算TIDE、IFNG等免疫治疗响应相关的signature。这部分如果后续在课题里用到了,可以单独开一篇展开聊。在实际操作中,我觉得IOBR最值得称道的地方是把繁琐的底层数据处理一下子收拢了,让你把精力放在解读结果和做决策上。用完这个包再回去看之前手工拼接多算法结果的经历,确实有一种“效率翻倍”的爽快。

最后再分享一个自己的习惯:每次用IOBR跑完整流程后,我会把表达矩阵、临床信息、R版本、IOBR版本号、随机种子、每个算法的参数全部记在一个session_info.txt里。这样做既方便自己复现,也方便将来写methods时直接抄素材。生信分析最怕的就是跑通一遍之后忘了当初怎么跑的,严谨的记录习惯能让你少走很多弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询