ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cibersort从原理到实操:用反卷积解析肿瘤免疫细胞浸润比例

Cibersort从原理到实操:用反卷积解析肿瘤免疫细胞浸润比例 做肿瘤免疫相关研究的人十有八九都会遇到一个需求手里是一堆bulk转录组数据芯片或RNA-seq想知道肿瘤组织里到底有哪些免疫细胞、各占多少比例。Cibersort就是这个场景绕不开的标准工具。它既不靠“富集打分”也不靠“单细胞注释”而是用“反卷积”的数学思路把一个混合组织的mRNA表达谱拆分成不同免疫亚群的比例。这篇教程面向两类读者一是刚入手生信、想在自己数据上跑通Cibersort的同学二是已经在跑、但经常被结果P值搞到怀疑人生的朋友。我会从原理讲到如何准备数据再分别演示在线版和本地R版两种跑法最后把之前踩过的坑和排查思路全整理出来。先说明一下这篇不是那种只教“点哪个按钮”的速查手册。Cibersort看似简单其实每一个参数背后都有代价和取舍。如果只是照着别人代码抄一遍换一批数据大概率会翻车。我会尽量把每个“为什么”都讲清楚这样你遇到问题能自己排查而不是到处找人求救。1. Cibersort是什么从反卷积到免疫细胞比例1.1 为什么需要Cibersort一个肿瘤组织切下来里面混杂着肿瘤细胞、成纤维细胞、血管内皮细胞、各种免疫细胞还有细胞外基质成分。普通bulk转录组测序测的是这个混合物的整体RNA表达就像把一锅汤打碎后再去分析“整锅汤里有哪些味道”但你分不清“咸味”到底来自盐还是酱油。很多关键问题恰恰需要这种分辨比如PD-1/PD-L1免疫治疗响应和CD8阳性T细胞浸润程度密切相关比如调节性T细胞Treg和M2型巨噬细胞过多往往提示免疫抑制微环境预后更差比如某些化疗药的疗效也受肿瘤相关巨噬细胞极化的影响。要在bulk数据上回答这类问题不能只靠“整体表达量高低”必须想办法拆出不同免疫亚群的构成比例。Cibersort就是干这件事的。它在2015年由斯坦福团队发表在Nature Methods上此后被引用了上万次几乎是肿瘤微环境研究中的“默认选项”。和xCell、MCPcounter、ssGSEA这些方法相比Cibersort最大的特点是基于反卷积它不是简单看某个基因集的富集分数而是试图还原细胞亚群在样本中的绝对或相对比例。这个差异决定了它在某些场景下更准但也带来了更多需要注意的细节。1.2 核心原理支持向量回归的“数学盲盒”要让小白也能理解我习惯用一个拆解公式来说观测到的混合表达谱 ≈ 各细胞亚群的比例 × 每个细胞亚群的标记基因表达谱用数学符号表达就是M P × B其中M是你的样本表达矩阵已知B是标记基因表达矩阵已知P是细胞亚群比例矩阵未知。Cibersort把B固定为自带的LM22矩阵——这是作者从大量纯化免疫细胞表达谱中构建的“指纹数据库”覆盖22种免疫细胞亚群一共用了547个标记基因。已知M和B要求P这在数学上就是一个反卷积问题。难点在于直接解这个方程在生物学数据上行不通。基因表达数据噪音大、不同基因动态范围差异悬殊、细胞比例还有非负约束。Cibersort选择使用支持向量回归Support Vector Regression, SVR来求解而不是普通最小二乘。我用生活化的方式解释SVR不会“一根筋”地去精确拟合每一个基因的表达值而是允许一定的误差范围更关注整体趋势。这就像你根据一屋子人的身高去猜年龄个别特例比如长得很高的初中生不会让你把整体判断带偏。SVR这个特性让Cibersort在高噪音、高维小样本的基因表达数据上表现稳定。LM22矩阵包含的22种细胞亚群包括naive和memory B细胞、CD8 T细胞、CD4 naive/memory/activated T细胞、Treg、gamma-delta T细胞、静息和激活NK细胞、单核细胞、M0/M1/M2巨噬细胞、静息和激活树突状细胞、静息和激活肥大细胞、嗜酸性粒细胞、中性粒细胞等。你要注意这里的比例是针对这22种免疫细胞内部的相对构成不是占所有组织的绝对比例。这是很多新手容易误解的第一件事。1.3 适用场景和不适用场景我自己的经验是Cibersort最适合两类研究场景。一类是验证类你有某个临床分组比如 responders vs non-responders想看看免疫细胞构成是否有差异这时Cibersort能给出一个直观的22维“画像”。另一类是探索类没有明确假设想知道哪些免疫细胞亚群与某个连续变量比如肿瘤突变负荷TMB相关可以用Cibersort结果做相关性分析和生存分析。不适合的场景也很明确。如果你手头是单细胞RNA测序数据不应该用Cibersort而应该用CIBERSORTx作者的升级版或直接做单细胞注释。如果你的组织压根没有明显免疫成分比如纯粹培养的细胞系、精子组织、或者某些类器官模型Cibersort结果一般会是“所有免疫细胞比例接近0P值全部不显著”这不一定是你操作错了而是生物学上就不该有免疫信号。还有一个容易被忽视的限制LM22只覆盖免疫细胞不包含肿瘤细胞、成纤维细胞、内皮细胞等所以它无法告诉你“肿瘤细胞占比多少”。2. 数据准备90%报错都发生在这里2.1 输入表达谱的格式要求先把Cibersort对输入文件的基本要求摆出来。在线版要求的输入是纯文本格式常见是制表符分隔的txt文件。矩阵结构是第一列是基因名gene symbol第一行从左往右依次是“Gene symbol”或其他列名加各样本名称后面的单元格全部是表达值。我画一个最简单的示例Gene S1 S2 S3 B2M 8.12 9.03 6.78 CD3D 4.21 5.34 3.87 CD8A 3.11 4.56 2.43 GZMB 2.32 3.11 1.98需要注意几个硬性规定。第一基因名必须是HGNC官方symbol比如CD8A、CCL5、CXCL9这种格式不要带版本号、不要带Ensembl IDENSG000001...或Entrez ID数字格式。第二行名不能有重复如果同一个基因名出现多行必须先合并。第三表达矩阵内不能有缺失值NA也不能出现“NaN”“Inf”这些特殊值上传前要检查一遍。第四样本名列名必须唯一重复列名会导致后面的结果解析混乱。这里头最坑的是很多人用Excel打开表达矩阵另存为文本。Excel有个“著名”的毛病会自动把某些基因名改成日期格式。比如MARCH1这个基因会被改成“1-Mar”SEPT9会被改成“9-Sep”DEC1会被改成“1-Dec”BMP6有时候也会被误识别。这种错误不报错、不警告Cibersort照样能跑但匹配到的基因数量骤减结果完全不可信。我的习惯是表达矩阵的清洗和处理全部在R里完成绝不经过Excel直接编辑。如果非要用Excel查看看完就关不要保存。2.2 芯片与RNA-seq数据的区别Cibersort早期发布的时代是芯片microarray的天下LM22标记基因矩阵本身的表达量也是基于芯片的log2尺度构建的。后来大家普遍用RNA-seq了官方说明也支持RNA-seq数据但有几个实操细节必须注意。首先是表达量单位的选择。RNA-seq建议使用RPKM、FPKM或TPM格式表达值不要直接塞整数型counts。原因很简单反卷积假设输入表达谱和LM22在数值尺度上具有可比性而counts的分布特点大量0、动态范围极大和芯片数据差异太大直接跑很容易让SVR拟合出现偏差。我自己的建议是如果是RNA-seq数据优先使用TPM然后做log2(x1)转换。有段时间我在处理TCGA数据时直接用原始counts跑结果22种免疫细胞的比例普遍被低估而且P值分布极差后来全部改成TPM log2重跑才正常。其次是关于quantile normalization分位数归一化的选择。Cibersort在线和本地脚本里都有一个QN参数默认是TRUE。这个参数的本意是消除不同样本之间的技术差异让表达值分布尽量一致。但它在RNA-seq数据上可能带来问题RNA-seq数据的表达值分布本来就和芯片不完全一致强行做分位数标准化反而可能引入批次伪影。有一个相对稳妥的策略如果芯片数据保持QNTRUE如果是RNA-seq数据、且样本之间测序深度差异不大可以尝试QNFALSE然后对比P值和相关性如果结果差异不大选更稳定更保守的方案。坦白说这个问题在社区里争论多年最靠谱的做法是两套都跑一遍在论文里说明你选择的依据。2.3 标记基因矩阵LM22的获取和校验LM22矩阵本身是公开的在Cibersort官方页面的下载区可以拿到解压后是一个名为LM22.txt的文件。第一列是基因名后面有22列每列对应一个免疫细胞亚群单元格数值代表该标记基因在该亚群中的相对表达水平。但这里有个很隐蔽的坑网上流传的“LM22.txt”版本并不统一。最原始版本是547个基因但后来有些人在GEO或GitHub上分享的版本会出现714个基因、或者顺序和列名略有差异。这不一定是什么大问题因为LM22在CIBERSORTx时代确实被作者更新过扩展了基因数量。但如果你想复现某篇已发表文献的结果最好使用与那篇文献一致的LM22版本。我的经验是先从官方渠道下载原始LM22.txt然后检查行数和列名是否与你预期一致。一个快速校验方法是在R里用dim()看矩阵维度应该大约是547行×22列加表头是548行。如果行数差很多说明版本不对建议重新下载。另外顺便说一句LM22文件的列名是带空格的细胞类型名称比如“T cells CD4 naive”“Macrophages M2”这种格式。后续如果你在R里做结果处理列名带空格会带来很多麻烦建议尽早用make.names()或gsub()把空格替换成下划线。3. 完整跑一遍Cibersort在线版与本地版双实操3.1 在线版分步演示访问Cibersort官网注册账号登录后进入分析页面。整个过程大致分四步。第一步上传你的表达矩阵。页面会要求你选文件支持txt格式。上传成功后系统会展示文件的前几行务必在这一步确认你的矩阵格式正确尤其是第一列是否真的是基因symbol而不是行号或Ensembl ID。第二步确认标记基因矩阵。系统默认加载LM22一般不用改动。如果你在本地下载了新版LM22也可以选择自定义上传。这里我建议优先使用网站内置的官方版本除非你有特殊理由。第三步设置运行参数。最关键的参数是Permutations置换次数推荐设置为1000。这个参数的意思是Cibersort会随机打乱数据1000次每次重新计算反卷积结果从而构建一个零分布用来评估你真实结果的显著性P值。置换次数越大P值估计越稳定但运行时间也越长。500次只是勉强能发布1000次是主流选择低于100次基本只有预实验结果才用。接下来是运行模式选项。默认是相对模式relative mode输出的是22种免疫细胞在“免疫细胞总量”中的构成比例每行样本的22个比例加起来约等于1。如果你勾选了绝对模式absolute mode也叫B-mode输出的是每个免疫细胞亚群在组织整体中的绝对评分。两者怎么选如果你的样本来自同一个类型的组织比如全是肺腺癌组织用相对模式就够如果你要比较不同来源样本之间免疫浸润的“绝对丰度大小”或者感觉某个样本免疫细胞总量本身就有显著差异建议同时跑绝对模式作为辅助证据。我个人的习惯是常规分析用相对模式必要的时候再补一个绝对模式的结果放在附件材料里。最后一步是点击提交并等待。在线版的运行时间取决于样本数、基因数和置换次数。一个100个样本、2万个基因、perm1000的矩阵通常需要几十分钟如果数据特别大可能要几个小时。页面会显示进度条但实际等待过程中不用一直盯着跑完会收到邮件通知。下载下来的结果是一个zip压缩包解压后里面有多个文件核心的是CIBERSORT-Results.txt。这个结果文件的结构是这样的第一列是样本名接着是22列免疫细胞亚群比例最后三列是P-value、Correlation、RMSE。注意相对模式下这22列比例的总和约等于1但并不是严格等于1因为会存在数值误差。3.2 本地R脚本运行详解在线版方便但有些场景它搞不定。比如你要批量处理几十个数据集、或者你需要完全可复现的流程、又或者在线版服务器排队太严重。这种情况建议用本地R脚本。Cibersort官方提供了一个R脚本文件名一般是CIBERSORT.R里面封装了整个反卷积流程。使用方式并不复杂# 先加载CIBERSORT.R脚本 source(path/to/CIBERSORT.R) # 运行核心函数 results - CIBERSORT( path/to/LM22.txt, # 标记基因矩阵 path/to/expressions.txt, # 你的表达谱 perm 1000, # 置换次数 QN TRUE, # 是否做分位数归一化 absolute FALSE # 是否绝对模式 )函数返回值是一个列表其中results$abs或results$relative包含了22个免疫细胞亚群的比例同时会附带P-value、Correlation、RMSE三列。为了后续分析方便我一般会这样处理# 提取核心结果并保存为csv write.csv(results, file cibersort_output.csv, quote FALSE)本地版有几个需要注意的地方。第一脚本运行依赖R包e1071SVR核心算法和parallel并行计算。如果报错说找不到e1071先install.packages(e1071)。第二Windows系统上如果perm设置较大比如1000脚本会自动启用并行计算。但如果你的机器核心数较少运行时间会明显上升。建议perm1000时至少4个核心起步。第三路径中的反斜杠在Windows下可能会出问题建议统一用正斜杠或file.path()拼接路径省得报错。本地版相比在线版的另一大优势是可控性更高。在线版是“黑盒”你只能等它跑完本地版则可以自己查日志、调参数、甚至修改脚本内部逻辑。如果你所在团队有标准化分析的规范要求推荐尽量把Cibersort纳入本地R pipeline这样从原始数据到最终图表都能完整复现。3.3 结果文件里最重要的三列很多新手拿到结果后第一件事就是直奔22列比例去看哪个细胞多哪个细胞少。正确姿势应该是先看最后三列质量指标。P-value是最关键的一列。它的含义是当前样本的观测表达谱能被LM22反卷积模型“稳定解释”的概率。P值越低说明拟合越可靠如果P值大于0.05说明反卷积结果和观测数据的吻合度没有显著优于随机水平这个样本的细胞比例数值就不能当真。Correlation列是被预测表达谱和观测表达谱的相关系数越高越好。RMSE是均方根误差越低越好。三者要一起看一个可靠的结果通常P值小于0.05、Correlation较高具体阈值因数据集而异、RMSE相对较低。我习惯在结果文件里加一列“QC_pass”只有P0.05且Correlation0.3的样本才标记为通过后续所有统计分析和图表只使用通过质检的样本。这虽然是个人经验但在审稿人眼里是加分项因为它表明你有严格的质量控制意识。4. 结果可视化与下游分析从比例矩阵到投稿级图表4.1 样本级别的堆叠条形图与箱线图拿到比例矩阵后最直观的是画堆叠条形图。每个样本一条柱子22种颜色代表22种免疫细胞亚群一眼就能看出不同组间构成的差异。ggplot2画这种图的思路是先把宽表转成长表library(ggplot2) library(reshape2) # results是Cibersort输出矩阵前22列是细胞比例 cell_fractions - results[, 1:22] cell_fractions$Sample - rownames(cell_fractions) long_df - melt(cell_fractions, id.vars Sample) long_df$Group - rep(group_vector, each nrow(cell_fractions)) ggplot(long_df, aes(x Sample, y value, fill variable)) geom_bar(stat identity, width 0.8) theme_bw() theme(axis.text.x element_text(angle 45, hjust 1)) labs(x , y Proportion, fill Cell type)如果你想比较不同临床分组之间的免疫细胞差异更常用的是箱线图加散点。对每个细胞亚群单独画一张箱线图或者把22个亚群放在同一张图里用分面展示。需要提醒的是Cibersort输出的比例数据通常不满足正态分布所以两组比较时不要用t检验优先选Wilcoxon秩和检验多组比较用Kruskal-Wallis检验。这是审稿人很容易盯住的统计细节。4.2 免疫细胞之间的相关性分析免疫细胞不是独立存在的它们之间往往形成网络。比如M2型巨噬细胞和Treg在免疫抑制微环境中常同步升高CD8 T细胞和NK细胞可能呈正协同。通过相关性分析可以把这种关系量化。做法很简单把通过QC的样本拿出来对这22列比例做Spearman相关性矩阵再用pheatmap画热图library(pheatmap) cor_mat - cor(cell_fractions, method spearman) pheatmap(cor_mat, display_numbers TRUE, number_format %.2f, color colorRampPalette(c(navy, white, firebrick3))(100))这张图放进文章的补充材料很合适可以直观展示“免疫抑制网络”的存在。不过这里有个统计上的隐藏问题Cibersort相对模式输出的比例是成分数据compositional data各成分之间此消彼长天然会带来负相关偏向。如果你发现很多负相关别急着当作生物学发现最好再说一句“考虑到比例数据的性质部分负相关可能是数学上的约束导致的”。审稿人看到你主动说明这一点会放心很多。4.3 与临床数据的整合思路最常见的下游分析是把免疫细胞比例和临床数据关联起来。比如你把某种关键免疫细胞如CD8 T细胞按中位数分成高表达组和低表达组用survival包做KM生存曲线library(survival) library(survminer) # 假设CD8A是你的目标免疫细胞 group - ifelse(results$T cells CD8 median(results$T cells CD8), High, Low) fit - survfit(Surv(OS_time, OS_status) ~ group, data clinical_data) ggsurvplot(fit, pval TRUE, risk.table TRUE)需要强调的是Cibersort给的是免疫细胞相对比例不是绝对计数所以做生存分析时结果受样本构成的影响比较大。尤其当样本中免疫细胞整体占比很低时某个亚群的相对比例可能虚高或虚低。我的建议是在做生存分析之前配合绝对模式结果或至少看一眼P-value分布如果大量样本P值不显著生存分析的结果可信度会打折扣。除了生存分析还可以把免疫细胞比例和TMB肿瘤突变负荷、MSI状态、免疫评分等指标做相关性分析或者比较不同免疫亚型和免疫细胞构成的关联。这些都是肿瘤免疫领域常见的高分文章素材但核心逻辑永远不要变Cibersort结果是“探索性证据”用它生成的假设必须经过实验或额外数据集验证不能当结论直接说死。5. 常见问题与灾难恢复实录5.1 基因名匹配率过低这个是最常见、也最隐蔽的问题。在线系统上传表达矩阵后不会给你“基因匹配率”的反馈只有下载结果后你才发现P值普遍很高比例分布也特别诡异。一个典型场景是你的表达矩阵用的是Ensembl ID。你心想“反正都是基因ID应该没问题吧”但实际上Cibersort内部拿你的基因ID和LM22的基因symbol做匹配能匹配上的可能连1%都不到结果自然完全没意义。解决方案是用biomaRt做ID转换library(biomaRt) ensembl - useEnsembl(biomart ensembl, dataset hsapiens_gene_ensembl) gene_map - getBM(attributes c(ensembl_gene_id, hgnc_symbol), filters ensembl_gene_id, values rownames(expr_matrix), mart ensembl) # 然后做匹配去掉没有symbol的行转换完成后还要检查是否有重复symbol。同一个symbol对应多个Ensembl ID时建议保留表达量均值最大的那个或者直接取所有重复行的均值。这一步处理干净了后面的匹配率才稳。5.2 P值大面积大于0.05如果跑完结果发现绝大多数样本的P值都大于0.05先从四个角度排查。第一是基因名格式有没有可能是Ensembl ID或Excel改名的锅。第二是数据单位是不是把counts直接塞进去了。第三是数据质量样本本身是否存在严重的批次效应或降解问题。第四是生物学因素样本里免疫细胞本来就极少比如某些分化程度很高的实体瘤组织。这里有个排查技巧先用ssGSEA或GSVA随便算一下免疫相关的整体富集分数如果连“免疫信号强度”都普遍很低那说明不是Cibersort的问题而是生物学事实。如果整体免疫信号不低但Cibersort P值普遍高那多半是数据预处理环节出了偏差重点检查单位、归一化方式、基因匹配率这三项。5.3 在线版和本地版结果不一致有时候同一份数据在线版和本地版跑出来的细胞比例差异不小。常见原因有三个一是LM22版本不一致在线版可能更新过而本地脚本用的是旧的二是QN参数设置不同比如在线版默认开QN而你本地关了三是perm数值不一样置换次数不同会引入随机波动。遇到这种情况把参数统一成同一套特别是用同一个LM22文件和同样的QN设置再跑一遍差异基本就消失了。如果还有偏差以本地版为准因为本地版可以固定随机种子完全可复现。5.4 运行时间过长的优化建议在线版提交后如果超过一天还在运转我建议直接放弃排队转本地版。本地版提速的几条实践经验把perm从1000降到500优先做预扫描用detectCores()确认并行核数对表达矩阵先过滤掉低表达基因例如在所有样本中平均表达量排名后50%的基因删掉输入维度小了SVR求解速度会快很多如果绝对模式和相对模式都要结果可以分两次跑而不是一次跑双模式。实测印象里一个100样本、2万基因的矩阵8核并行、perm1000大概30到60分钟能跑完。如果跑了两小时还没动静一般是并行没生效检查一下parallel包是否被正确调用或者Windows平台下SOCK集群初始化是否有问题。5.5 常见报错速查表我把这些年遇到的典型报错整理成一个速查表方便你对着排查。报错现象可能原因解决方式no lines available in input文件为空或路径错误检查txt文件内容重新上传subscript out of boundsLM22列名与你代码中的列名不匹配用colnames()查看列名统一命名object svm not founde1071包未加载install.packages(e1071)后library(e1071)结果全是NA表达矩阵存在空值或Inf清洗数据填补或删除NA/Inf行运行时间异常长并行未启用或perm太大降低perm检查parallel包过滤基因22列比例总和远大于1或很小使用了相对/绝对模式理解错误确认absolute参数解读时注意模式含义基因匹配率极低基因ID格式不对用biomaRt转换到HGNC symbol最后再分享一个小习惯我会在每次跑Cibersort前把所有输入文件和参数写到一个txt记录里包括LM22版本、perm、QN、absolute这些信息。这样不管是写文章还是将来复查都能准确说明当时是怎么算的。生物信息学最怕的不是结果差而是结果说不清来源。Cibersort本身只是一个工具它的价值取决于你怎样使用它。在你盯着那22列比例做各种下游分析之前先花几分钟确认你的输入数据、质量指标和参数选择都站得住脚这会让你后面的每一步都稳健很多。
返回列表