细胞通讯分析:CellChat
跟完这篇,您能把一份已经注释好细胞类型的单细胞数据,做成「哪类细胞通过哪条信号通路在跟哪类细胞对话」的结论:会算配体-受体通讯、读懂细胞通讯网络图、比较两组之间的通讯差异,也清楚这些结论到底能说到哪一步、不能说什么。
单细胞数据把一块组织拆成了一个个细胞,但细胞不是各自孤立的——它们靠分泌配体、被别的细胞的受体接收来彼此协调。CellChat 做的事,就是根据每类细胞里配体和受体基因的表达量,推断「发信号的细胞」和「收信号的细胞」之间可能存在多强的通讯,并把成百上千对配体-受体归拢成信号通路来看。请先记住一个词:推断。CellChat 给出的是基于表达量算出来的「通讯概率」,是待验证的假说,不是细胞之间真发生了对话的证据。这条边界贯穿全篇,末节会专门讲。
开始之前:您手上要有什么
CellChat 是注释之后的一步,动手前请确认两样东西已经就绪:
- 一份 log 标准化后的表达矩阵:基因 × 细胞,用的是标准化后的数据(Seurat 的
data层,即NormalizeData的结果),不是原始 counts。 - 一列可靠的细胞类型标签:每个细胞归到哪一类,这一列的质量直接决定通讯结果的质量。标签错了,后面算得再漂亮也是错的。注释怎么做、怎么核对,见 细胞注释:手动 marker 与自动 SingleR。
CellChat 的输入可以直接从 Seurat 对象里取:
library(CellChat)
library(Seurat)
# 从 Seurat 对象取 log 标准化数据与细胞类型标签
data.input <- GetAssayData(seu, assay = "RNA", slot = "data") # 基因 × 细胞
meta <- data.frame(labels = Idents(seu), row.names = colnames(seu))
物种要对上:人用
CellChatDB.human,小鼠用CellChatDB.mouse,别混。基因命名(人用大写、小鼠首字母大写)也要和数据库一致。
第一步:建对象、选配体-受体数据库
先把表达数据和细胞标签包成一个 CellChat 对象,再挂上一套配体-受体数据库——这套库就是「已知哪些配体配哪些受体」的字典,所有推断都以它为准。
# 建对象,group.by 指向 meta 里的细胞类型那一列
cellchat <- createCellChat(object = data.input, meta = meta, group.by = "labels")
# 挂数据库(人)
CellChatDB <- CellChatDB.human
cellchat@DB <- CellChatDB
CellChatDB 把配体-受体对分成三类,可按研究问题只取其中一部分:
| 类别 | 含义 | 什么时候用 |
|---|---|---|
Secreted Signaling | 分泌型信号(配体扩散出去被远处受体接收) | 最常用,关注旁分泌 / 内分泌式通讯时选它 |
ECM-Receptor | 细胞外基质与受体 | 关注细胞与基质互作时 |
Cell-Cell Contact | 需要细胞直接接触的信号 | 关注贴身接触型通讯时 |
只想看分泌型信号,就先把数据库子集出来再挂:
# 只取分泌型信号;不加这步则用全库
CellChatDB.use <- subsetDB(CellChatDB, search = "Secreted Signaling", key = "annotation")
cellchat@DB <- CellChatDB.use
第二步:算通讯概率
这一步是核心。先做预处理(挑出在各类细胞里显著表达的基因和对应的配体-受体对),再按「质量作用定律」的思路,用配体和受体的表达量算出每一对「发送细胞类型 → 接收细胞类型」在每条信号上的通讯概率。
# 预处理:挑显著表达的基因,再据此挑出有表达支撑的配体-受体对
cellchat <- subsetData(cellchat)
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- identifyOverExpressedInteractions(cellchat)
# 算通讯概率(配体-受体层面),并对结果做置换检验给出 p 值
cellchat <- computeCommunProb(cellchat)
# 过滤:一类细胞数太少,通讯估计不可靠,直接剔除
cellchat <- filterCommunication(cellchat, min.cells = 10)
# 归并到信号通路层面,再把网络按细胞类型对聚合
cellchat <- computeCommunProbPathway(cellchat)
cellchat <- aggregateNet(cellchat)
几点要知道:
computeCommunProb默认用type = "triMean",倾向于给出更少但更强的通讯,结果更保守。它同时跑置换检验,给每一对配体-受体一个 p 值——所以「通讯概率」和「是否显著」是两码事,都要看。filterCommunication(min.cells = 10)是常用惯例,非铁律:细胞数太少的类别,表达均值抖动大,通讯估计不可信。数据里稀有细胞多可适当调整,但要清楚放宽后这些类别的结论更该谨慎。- CellChat 有两个层级:配体-受体对(细)和信号通路(粗)。一条通路(如
TGFb)往往由多对配体-受体共同构成,看通路更稳、看具体配体-受体对更细。
想把推断出的显著通讯拉成一张表逐条看,用 subsetCommunication:
# 每行是一对「发送类型 → 接收类型 + 某配体-受体对」,带 prob 和 pval
df.net <- subsetCommunication(cellchat)
head(df.net)
读懂网络图
CellChat 最常看的是一张圆形网络图:每个点是一类细胞,点之间的连线表示通讯,箭头方向是「配体发送方 → 受体接收方」。有两种权重,别看混:
- 数量(count):两类细胞之间有多少对显著的配体-受体在通讯。
- 强度(weight):这些通讯的概率加总,代表通讯的「量级」。
groupSize <- as.numeric(table(cellchat@idents))
par(mfrow = c(1, 2))
# 左:通讯数量;右:通讯强度
netVisual_circle(cellchat@net$count, vertex.weight = groupSize,
weight.scale = TRUE, label.edge = FALSE, title.name = "通讯数量")
netVisual_circle(cellchat@net$weight, vertex.weight = groupSize,
weight.scale = TRUE, label.edge = FALSE, title.name = "通讯强度")
读这张图的顺序:
- 先看谁连谁:线越粗,两类细胞之间通讯越多 / 越强;没有线就是没算出显著通讯。
- 看方向:箭头从发送方指向接收方。同一对细胞可能双向通讯,粗细未必对称。
- 数量 ≠ 强度:可能配体-受体对不多,但每一对都很强(强度高、数量低);反之亦然。两张图对照着看。
想聚焦某一条通路,或想看具体是哪些配体-受体对在起作用:
# 单看某条通路的通讯网络
pathways.show <- c("TGFb") # 换成您数据里显著的通路名
netVisual_aggregate(cellchat, signaling = pathways.show, layout = "circle")
# 热图:行列是细胞类型,颜色深浅是该通路的通讯强度
netVisual_heatmap(cellchat, signaling = pathways.show, color.heatmap = "Reds")
# 这条通路里,各配体-受体对各贡献了多少
netAnalysis_contribution(cellchat, signaling = pathways.show)
想在指定的发送方、接收方之间,一次看清哪些配体-受体对显著,用气泡图——点大小代表显著性、颜色代表通讯概率:
# sources.use / targets.use 填细胞类型的编号或名称
netVisual_bubble(cellchat, sources.use = 1, targets.use = c(2, 3, 4),
remove.isolate = FALSE)
谁在发信号、谁在收
除了「谁连谁」,还常问「哪类细胞是通讯枢纽」。CellChat 用网络中心性来刻画每类细胞在一条通路里的角色:主要发送者(sender)、主要接收者(receiver)、中介者(mediator)、影响者(influencer)。
# 先算每条通路的网络中心性
cellchat <- netAnalysis_computeCentrality(cellchat, slot.name = "netP")
# 看某条通路里各细胞类型分别扮演什么角色
netAnalysis_signalingRole_network(cellchat, signaling = pathways.show,
width = 8, height = 2.5)
# 二维散点:横轴总发送强度、纵轴总接收强度,一眼看出谁主发、谁主收
netAnalysis_signalingRole_scatter(cellchat)
散点图右下方的细胞类型是「话多的发送者」,左上方是「主要在听的接收者」,右上方则是又发又收的通讯核心。这一步帮您从一堆连线里,快速锁定值得深挖的细胞类型和通路。
组间通讯差异怎么比
真正有生物学价值的问题,往往是「病例组比对照组,通讯多了还是少了、哪条通路变了」。CellChat 的做法是:两组各自独立跑完上面全套,得到两个 CellChat 对象,再合并来比。
# cellchat.NL、cellchat.LS 是两组各自跑完的对象;标签必须完全一致
object.list <- list(NL = cellchat.NL, LS = cellchat.LS)
cellchat <- mergeCellChat(object.list, add.names = names(object.list))
第一层,比总量——两组的通讯总数量、总强度谁高谁低:
compareInteractions(cellchat, show.legend = FALSE, group = c(1, 2))
compareInteractions(cellchat, show.legend = FALSE, group = c(1, 2), measure = "weight")
第二层,看差异网络——红色代表在第二组里增强、蓝色代表减弱,直接看出哪对细胞之间的通讯变了:
par(mfrow = c(1, 2))
netVisual_diffInteraction(cellchat, weight.scale = TRUE) # 数量之差
netVisual_diffInteraction(cellchat, weight.scale = TRUE, measure = "weight") # 强度之差
第三层,把通路按「信息流」排序,看哪些通路在两组间此消彼长,do.stat = TRUE 会做显著性检验:
# stacked = TRUE 看相对占比,FALSE 看绝对值;两组同一通路并排比
rankNet(cellchat, mode = "comparison", stacked = TRUE, do.stat = TRUE)
rankNet(cellchat, mode = "comparison", stacked = FALSE, do.stat = TRUE)
比较分析的三条纪律:
- 两组的细胞类型标签必须一致:类别名、粒度都要对齐,否则「差异」里混着的是注释口径的差异,不是生物学差异。
- 别只盯绝对量:一组细胞数多、测序深,通讯总量天然偏高。
stacked = TRUE看相对占比,能抵消一部分这种规模差异。 - 差异要落到通路和配体-受体上:说「A 组通讯更强」意义有限,要能指到「是 TGFb 通路在某对细胞间增强了」,才是可跟进、可验证的结论。
结论解读的边界
这是全篇最该慢下来读的一节。CellChat 的结论用错地方,比不做还糟。
| 说法 | 能不能这么说 | 为什么 |
|---|---|---|
| 「A 细胞和 B 细胞之间可能存在 TGFb 通讯」 | 可以 | 这是基于表达量的推断、待验证的假说 |
| 「A 细胞正在给 B 细胞发 TGFb 信号」 | 不能 | CellChat 只看 mRNA 表达,没测蛋白、没测结合、没测下游是否真被激活 |
| 「这条通讯导致了表型变化」 | 不能 | 相关不等于因果,快照数据说不了因果和时序 |
| 「通讯概率 0.8 比 0.4 强一倍」 | 谨慎 | 它是相对打分,不是真实概率,跨数据集直接比数值不可靠 |
几条务必记住的局限:
- 推断,不是测量。通讯概率来自配体、受体基因的表达量,走的是「表达高 → 可能通讯强」的逻辑。mRNA 高不等于蛋白高,蛋白在不等于真的结合、真的激活了下游。所有结论都是待实验验证的假说。
- 依赖数据库,且数据库不完整。没被收录的配体-受体对,CellChat 一律看不到;库以外的通讯不会出现在结果里,「没算出来」不等于「不存在」。
- 不含空间信息。标准 CellChat 不知道两类细胞在组织里是不是真挨得够近。分泌型信号还好,接触型信号尤其要留意——表达对得上,物理上够不着也白搭。
- 对细胞数敏感。
min.cells之下的类别被剔除;即便留下,稀有类别的通讯估计也更抖、更该谨慎。 - 是筛线索的工具。CellChat 的正确用法是从全景里筛出值得深挖的通讯,再拿共染、配体受体阻断、体外共培养等实验去验证——它给的是方向,不是定论。
一句话收尾:把 CellChat 的输出当成「值得下一步验证的候选通讯清单」来用,而不是当成「细胞对话的实况记录」。
在平台上跑一遍
上面从建对象到组间比较的整套流程,在「百沐一下」不写代码也能走完:上传注释好的单细胞数据(要有细胞类型那一列),用一句话说清目的——例如「用 CellChat 分析这份人外周血数据的细胞通讯,再比较 disease 和 control 两组的通讯差异」,平台会自动完成建库、算通讯概率、出网络图与差异图,并连同结果表和可复现的 R 代码一起交付。功能说明见 组学分析助手使用指南,或直接到 app.baimuyixia.com 试一遍。
相关
- 细胞注释:手动 marker 与自动 SingleR —— 通讯分析的上一步,标签质量决定结果质量
- 单细胞分析全流程:Seurat 标准 pipeline —— 从质控到注释的完整脉络,通讯分析在其后
- 富集分析:GO / KEGG / GSEA —— 拿到差异通讯后,进一步看它们落在哪些功能上
- 组学分析助手使用指南 —— 在平台上零代码跑通细胞通讯分析