跳到正文
百沐一下百沐一下
本节目录

细胞注释:手动 marker 与自动 SingleR

跟完这篇,您能把一张已经聚好类的单细胞图谱,从「第 0 群、第 1 群」这样的编号,落实成「CD8 T 细胞、单核细胞、B 细胞」这样的生物学身份:既会用 marker 手动判读,也会用 SingleR 自动打分,还知道两者怎么互相印证、一个标签到底可不可信怎么看。

聚类只把细胞按表达相似度分成了若干群,群还只是编号。注释就是给每个群贴上细胞类型标签。做法分两条路:一条是手动 marker 法,靠已知的标志基因人工判读;一条是自动注释,让算法拿参考数据集给每个细胞打分。两条路各有长短,稳妥的做法是都跑一遍、互相对照。

开始之前:您手上要有什么

注释是聚类之后的一步,动手前请确认两样东西已经就绪:

  1. 一份聚过类的 Seurat 对象:已经跑完标准化、降维、FindClustersIdents()seurat_clusters 里是群编号。聚类怎么做,见 单细胞聚类:从降维到分群
  2. log 标准化后的表达数据FindAllMarkers 和 SingleR 都在标准化后的表达上工作(Seurat 的 data 层,即 NormalizeData 的结果),不是原始 counts。

注释的目标不是「给每个群硬塞一个名字」,而是在有把握的地方下明确判断,在没把握的地方老实标成「待定」。宁可留一个 Unknown,也不要凭一个不特异的基因乱认。

如果对象做过整合(多样本用 CCA、Harmony 等对齐过),默认 assay 可能是 integratedSCT,那里只留了部分基因、也不是用来做差异的层。找 marker 前先把默认 assay 切回原始表达:DefaultAssay(seurat) <- "RNA"

手动 marker 法

手动法分两步:先让每个群自己「交出」区分性最强的基因,再拿这些基因去比对已知的细胞类型标志。

先摆一眼两条路的性格,好知道各自该派什么用场:

维度手动 marker 法自动注释(SingleR)
依据已知标志基因 + 人工判读参考数据集 + 相关性打分
速度慢,逐群看快,一次跑完
可复现依赖经验,不同人可能给不同结论参数固定,结果可复现
短板费时、要懂组织的生物学背景只和参考数据集一样好,库里没有的类型会被硬套
最适合定案、确认稀有或组织特有类型快速起底、给手动判读提供线索

第一步:找各群的 marker

FindAllMarkers 对每个群做「本群 vs 其余所有细胞」的差异检验,找出每群特异高表达的基因。

library(Seurat)
library(dplyr)

# 若对象整合过,先把默认 assay 切回原始表达再找 marker
DefaultAssay(seurat) <- "RNA"

# seurat 已完成聚类;默认用 Wilcoxon 秩和检验
markers <- FindAllMarkers(
  seurat,
  only.pos = TRUE,        # 只要上调的,即本群相对高表达的基因
  min.pct = 0.25,         # 至少在 25% 的本群细胞里检出:常用惯例,按需调
  logfc.threshold = 0.25  # log2FC 门槛:常用惯例,不是铁律
)

# 每群取 avg_log2FC 最高的前若干个,作为候选 marker
top <- markers %>%
  group_by(cluster) %>%
  slice_max(avg_log2FC, n = 10)

FindAllMarkers 的输出每行是「某个基因在某群」,关键列有:avg_log2FC(本群相对其余的 log2 倍数变化)、pct.1 / pct.2(在本群 / 其余群的检出比例)、p_val_adj(校正 p 值)。一个好 marker 的特征是 pct.1 高、pct.2——在本群普遍表达、在别处几乎不表达。

第二步:比对已知细胞类型

拿每群的 top marker 去对照该组织里公认的标志基因。下面是外周血单个核细胞(PBMC)里一些常被引用的经典 marker,供体会「怎么比对」,不同组织要换成对应的标志基因:

细胞类型常用标志基因
T 细胞(总)CD3DCD3E
CD4 T 细胞IL7RCD4
CD8 T 细胞CD8ACD8B
B 细胞MS4A1(CD20)、CD79A
NK 细胞NKG7GNLY
单核细胞CD14LYZ
树突状细胞FCER1A

表里是示例,不是清单。每种组织、每个课题的 marker 都不一样,请以您所在领域公认的标志基因为准(可查 CellMarker、PanglaoDB 等公开数据库,或对照同组织的经典文献)。

判读时别只看一个基因是否表达,要看它是否只在这一群里表达DotPlot 把这件事画得最清楚——一个基因的点若只在某一群又大又深、在别群又小又浅,才是可信的判据。

# 挑一组候选 marker,一次看清各群的表达分布
DotPlot(seurat, features = c("CD3D", "CD8A", "MS4A1", "CD14", "NKG7", "LYZ")) +
  RotatedAxis()

# 换个角度核验同一件事,两图配合看更踏实:
VlnPlot(seurat, features = c("CD3D", "CD14"))        # 各群的表达分布(小提琴图)
FeaturePlot(seurat, features = c("CD8A", "MS4A1"))   # 把表达画到 UMAP 上,看落在哪群

判定清楚后,把编号换成细胞类型名:

new.ids <- c("0" = "CD4 T", "1" = "CD14 Mono", "2" = "B",
             "3" = "CD8 T", "4" = "NK")            # 按您的判读结果填
seurat <- RenameIdents(seurat, new.ids)
seurat$cell_type <- Idents(seurat)                  # 存一列,便于后续引用

自动注释:SingleR 打分

手动法准,但慢、依赖经验。自动注释反过来:快、可复现,代价是结论只和参考数据集一样好。SingleR 是常用的一种,思路是拿一套已标注好的参考表达谱,为每个细胞(或每个群)跟各参考类型算相关性、打分,取分最高的类型作标签。

第一步,选参考数据集。celldex 包提供了几套现成的参考,按样本类型选:

参考数据集(celldex)适用
HumanPrimaryCellAtlasData()人,覆盖面广、类型多
BlueprintEncodeData()人,免疫与基质细胞
MonacoImmuneData()人,免疫细胞分得细

第二步,把 Seurat 对象转成 SingleR 认的格式并打分。SingleR 有两种粒度:

library(SingleR)
library(celldex)

ref <- HumanPrimaryCellAtlasData()          # 选一套参考
sce <- as.SingleCellExperiment(seurat)      # Seurat -> SingleCellExperiment

# 粒度一:逐细胞注释
pred <- SingleR(test = sce, ref = ref, labels = ref$label.main)
seurat$singler <- pred$labels

# 粒度二:逐群注释(拿聚类结果做单位,结果更稳、更省算力)
pred_cl <- SingleR(test = sce, ref = ref,
                   labels = ref$label.main,
                   clusters = seurat$seurat_clusters)
  • label.main 是粗粒度标签(如 T_cells),label.fine 更细(如具体亚型)。先用 main 看大类,需要再上 fine
  • 逐群注释(给 clusters 参数)通常比逐细胞更稳:单个细胞噪声大,落到群上做多数投票更抗噪,也更省时间。

两者互相印证

手动和自动,谁也不该单独定案。真正让人放心的,是两条独立的路走到同一个结论。做法很直接:把 SingleR 的标签和您手动判读的身份放到一张表里对照。

# 把逐细胞 SingleR 结果与手动注释交叉列表
table(manual = seurat$cell_type, singler = seurat$singler)

看这张交叉表,三种情况分别处理:

  1. 两者一致:手动认成 B 细胞、SingleR 也判 B 细胞——这一群基本可以定案。
  2. 粗细之差:手动只到「T 细胞」,SingleR 分到「CD8 T」。不矛盾,是互补,可采用更细的那个(但要回头用 marker 确认细分站得住)。
  3. 明确冲突:手动认 NK、SingleR 判单核。这是警报,别急着信任何一方——回去看这群的 marker 是不是不特异、是不是两类细胞混在了一群(见下文「常见坑」)。

参考数据集里没有的细胞类型,SingleR 只会硬套最接近的已知类型,不会说「不认识」。所以自动注释给出的类型,一定要用 marker 回验一遍,尤其是参考库里可能缺失的稀有类型或您组织特有的类型。

注释可信度怎么判断

一个标签贴上去,得能说清「凭什么」。判可信度看两个维度:marker 够不够特异、群本身纯不纯。

marker 特异性——好的判据是「本群有、别群无」:

  • DotPlot 里该 marker 只在目标群又大又深,别群点小色浅;
  • FindAllMarkers 结果里 pct.1 高而 pct.2 低;
  • 若一个「marker」在半数群里都表达,它就不特异,别拿它当判据。

SingleR 的把握度——SingleR 自带两个诊断量:

# 每个细胞对各参考类型的打分热图:好的注释应「独高一峰」
plotScoreHeatmap(pred)

# delta 分布:最高分与其余分的差距,差距越大越可信
plotDeltaDistribution(pred)

pred$pruned.labels 是 SingleR 剔除低置信后的标签:把握不足的细胞会被置成 NANA 当成「模型也拿不准」的诚实信号,不要强行填一个类型。

群纯度——一个群若是干净的单一类型,它的 marker 会集中、SingleR 打分会一致;若一群里同时冒出两套互斥的 marker(比如既有 T 细胞的 CD3D 又有单核的 CD14),说明这群很可能没分开,注释也就无从可信。

常见坑

表现怎么办
marker 不特异拿来判读的基因在多群都表达,认谁都像优先选 pct.1 高、pct.2 低的基因;一个类型用一组 marker 交叉印证,别靠单基因
分辨率过高,一类被切碎同一种细胞被拆成好几群,marker 几乎一样调低 FindClustersresolution;marker 高度重叠的相邻群可考虑合并
分辨率过低,多类混一群一群里同时有互斥 marker(如 CD3DCD14调高 resolution 重新分,或对该群单独再聚类
参考库里没有的类型SingleR 硬套一个最接近的已知类型换更贴合的参考;一律用 marker 回验,稀有或特有类型尤其要查
双细胞(doublet)一小群同时高表达两谱系的 marker上游用 doublet 检测标记并剔除,别把它当成一种「新细胞类型」
迷信自动、跳过回验SingleR 给了标签就直接采用自动结果永远用 marker 复核,冲突的群务必查清
在整合层上找 marker忘了切 assay,marker 数目少、结果奇怪找 marker 前 DefaultAssay(seurat) <- "RNA"

分辨率没有「正确值」。resolution 调大分得细、调小分得粗,合适与否取决于您要区分到多细的类型。惯常做法是试几个值,看哪个能让已知细胞类型恰好各成一群——这本身也要靠 marker 来判断,具体怎么调见 单细胞分辨率:分群该多细

在平台上跑一遍

不想装 Seurat、SingleR,也能完成整套注释:在 百沐一下 传入聚好类的单细胞对象,用一句话说清目的——「给各群做细胞注释,先跑 marker、再用 SingleR 对照,物种是人、组织是外周血」,平台会自动找各群 marker、调参考数据集打分、把两者交叉对照,并连同 DotPlot、打分热图和可复现的 R 代码一起交付,可信度存疑的群会替您标出来。用法见 组学分析助手使用指南

相关