在实际分析单细胞转录组数据的时候,最磨人的往往不是跑流程,反而是最后那一关:拿到UMAP图,面对一堆数字编号的cluster,你要一个一个告诉别人这是什么细胞。这个环节做得好,整篇文章的生物学故事就立得住;做得糊弄,审稿人随便一眼就能看出注释经不起推敲。关于单细胞亚群人工注释,很多入门教程只讲“用FeaturePlot看一眼marker然后命名”,但实操中远远不止这些。这篇我会把从标记基因搜集、特征可视化、打分验证,到亚群功能分析的完整流程串起来,每一步都讲清楚怎么做、为什么这么做,以及最常见的坑在哪里。
这套流程并不依赖高级编程技巧,只要你会基础的Seurat操作,耐心跟着做就能完成一个靠谱的人工注释。适合正在处理10x Genomics或类似平台单细胞数据、需要自己搞定细胞类型鉴定的朋友,也适合想系统梳理注释思路、避免凭感觉命名的研究者。
1. 注释前的准备:不要把命运交给默认参数
很多教程上来就教你用FindAllMarkers找差异基因然后查数据库,但实际操作中这一步跑得太快往往会翻车。人工注释的第一步不是查基因,而是先确认你拿到的聚类结果到底靠不靠谱。
1.1 聚类质量检查是注释的大前提
注释本质上是在给聚类结果贴标签,所以聚类本身如果有问题,后面所有注释都会失真。你至少需要确认三件事。
第一,聚类分辨率是否合理。不少默认流程用0.5或0.8固定的resolution跑完就完事了,但不同组织、不同样本的最佳分辨率差异很大。判断标准很简单:去看不同分辨率下的聚类数变化,以及UMAP图上cluster边界是否清晰。如果一批细胞被切得稀碎,或者完全分不开,说明分辨率不合适,需要重新聚类再注释。
第二,是否有明显的批次效应干扰。如果你合并了多个样本,先看各个样本在UMAP上的分布。如果同一个生物学类型的细胞因为样本来源不同而各自聚成一团,说明批次效应没有完全消除,这时候注释出来的亚群很可能是“伪亚群”。建议先用Harmony或CCA整合后重新聚类再注释。
第三,有没有明显的低质量细胞群混在里面。通常低质量细胞表现为线粒体基因比例高、基因数少,在图上会形成一个小而紧凑的独立cluster。这个集群如果不处理就注释,经常会被误判成某种特殊细胞类型,比如注释成巨噬细胞或应激细胞,实际上就是死细胞碎片或破损细胞的聚合。
我在实际项目中见过不少次这种情况:一个cluster高表达线粒体基因、低表达核糖体基因,看起来低质量,但就是挤在细胞群里没有被过滤掉。这类cluster建议尽早去除,或者在注释时明确标注为低质量群,不要硬着头皮给一个生物学名字。
1.2 用已知marker初步判断聚类是否正常
在正式开始注释之前,我会先用一批泛细胞类型marker快速扫一遍整体格局,确认各主要谱系是否分开了。比如用PTPRC(CD45)看免疫细胞总群,EPCAM看上表皮细胞,PECAM1看内皮,COL1A1看成纤维,CD3D看T细胞,MS4A1看B细胞,LYZ看髓系细胞。
这一步用FeaturePlot和DotPlot快速过一遍,大致判断每个cluster属于哪个谱系。如果某个cluster同时高表达好几个谱系的marker,很可能是双细胞,或者是一个混杂群,需要进一步细分或剔除。
这一轮的目的不是精确注释,而是确认大方向没搞错。如果这一步发现某些谱系的marker混杂严重,我通常会回头重新做整合或重新选高变基因,而不是硬着头皮继续注释。因为聚类如果在这个层面就没分开,后面用已知marker怎么注释都是别扭的。
2. 标记基因从哪来:建立可靠的marker清单
人工注释的核心资源就是标记基因清单。很多新手的做法是临时百度或者翻一两篇文献找几个基因,然后就开始命名。这种做法风险很高,因为不同组织、不同条件下的marker特异性差异很大。可靠的marker清单应该从多个来源交叉验证。
2.1 常用单细胞标记基因数据库对比
我平时最常查的数据库有这几个,各有特点,建议结合使用。
CellMarker数据库算是比较经典的,覆盖人和小鼠的多种组织,每个细胞类型都标注了标记基因及支持文献,注释到亚型级别也很方便,适合先查大类和亚类的候选marker。
PanglaoDB的特点是整理了单细胞测序实际验证过的marker,而且支持直接下载适用于Seurat的marker基因列表文件,用起来很方便。物种覆盖不如CellMarker全,但人鼠常用组织足够用。
SingleR则不太一样,它是一个基于参考转录组的自动注释工具,内置了多种参考数据集。虽然这个方法本身适合快速粗注释,但我更喜欢把它当作“辅助建议”来用,用来跟人工注释结果做印证。
另外还有CellTypist,这个是基于机器学习模型训练出来的,覆盖了很多组织,注释速度快,尤其对免疫细胞效果还不错。
这几个数据库我在做注释时都会有选择地参考。一般流程是:先用CellMarker查经典文献支持的marker,再用PanglaoDB看看有没有额外的候选基因,最后跑一个SingleR或CellTypist看自动注释的结果跟我的判断是否一致。三方对得上,这个注释就比较稳。
表格整理一下这几个资源的特点,方便你快速选型:
| 资源 | 特点 | 适合场景 | 局限性 |
|---|---|---|---|
| CellMarker | 文献整理、人鼠覆盖广、支持亚型 | 查询经典marker、写方法学描述 | 有些marker特异性不够高,需人工甄别 |
| PanglaoDB | 单细胞实测数据、支持Seurat格式导出 | 快速拿一篮子marker列表 | 组织覆盖有偏好,某些罕见细胞类型缺失 |
| SingleR | 自动注释、多参考数据集 | 作为人工注释的交叉验证 | 结果依赖参考集,罕见群体容易错 |
| CellTypist | 机器学习模型、免疫细胞效果好 | 大批量快速初筛 | 对非免疫细胞或特定组织支持有限 |
2.2 从文献和差异基因中挖掘亚群marker
数据库只是一个起点。对于你要研究的核心细胞类型,我强烈建议专门花时间查一下该组织或疾病模型中近三五年的单细胞文献。理由很简单:数据库里的marker往往是“普遍适用”的,但你的数据可能来自特殊处理条件或罕见亚型,这时候文献里特异性更高的marker组合会更可靠。
比如注释肿瘤浸润T细胞时,CD3D、CD8A只能告诉你这是CD8阳性T细胞,但要区分耗竭T细胞和效应记忆T细胞,你需要参考PDCD1、CTLA4、HAVCR2、LAG3这些抑制性分子的组合,或者IL7R、TCF7区分记忆类群。这些细节在经典数据库里更新得不够及时,但在最新文献里能找到很好的组合方案。
另一个容易被忽视的marker来源是你的FindAllMarkers结果。有时候你的数据里存在一个基因高表达、又恰好是某类细胞的核心转录因子,数据库里没收录,但文献支持它的角色。这时候不要因为数据库里没有就忽略,而是要在注释依据里写清楚“基于某基因表达及文献XX支持”,合理引用即可。
2.3 用差异表达结果甄别marker的辨别力
拿到一份候选marker列表后,在正式注释前我会做一个简单但很关键的验证:看看这些marker在你自己的数据里到底有没有辨别力。有些marker在文献里很经典,但在你的数据里可能因为测序深度、dropout效应等因素表达量低,肉眼根本分不出来。
做法很简单,用FindAllMarkers跑出每个cluster的差异基因后,把候选marker跟差异基因列表交叉对比。如果一个公认marker在对应的cluster里连top差异基因都排不进,那它在注释时就不太能支撑结论。相反,如果某个差异基因显著上调而且恰好有文献支持,那就能作为补充依据。
这个步骤能有效避免一个常见尴尬:FeaturePlot画出来一片糊,谁都分不出哪个是阳性群,但你还是硬着头皮给它命名。使用数据本身去验证marker的有效性,才是注释可靠的基础。
3. 人工注释实操:从粗放到精细的四步走
拿到靠谱的聚类结果、整理好marker清单之后,就可以正式开始注释了。我把这套流程拆成四个步骤,每一步都有明确产出,不容易混乱。
3.1 第一步:用FeaturePlot快速全局扫描
这个阶段我用一组泛谱系marker对全UMAP做快速扫描,判断每个cluster大致属于哪个细胞大类。我会把FeaturePlot的结果拼在一起看,这一步用的是FeaturePlot函数,代码很简单:
features <- c("PTPRC", "CD3D", "CD14", "MS4A1", "PECAM1", "COL1A1") FeaturePlot(seu, features = features, ncol = 3, order = TRUE)注意,order = TRUE这个参数很关键,它会让高表达细胞点叠加在低表达点上面,视觉上阳性群更清楚,尤其是表达量跨度大的基因。不加这个参数时,高表达的零散亮点容易被低表达背景淹没。
做完这一步,我会在笔记本里画一个简单的关系表:cluster编号对应可能的谱系。注意,这一步不要求精确到亚型,只要大类对应得上就行。如果某几个cluster在同一谱系内,后面再用亚型marker细分。
3.2 第二步:用平均表达量打分量化判断
光靠肉眼看图容易误判,尤其是遇到表达水平模糊的marker。我的做法是在FeaturePlot之后,再跑一个平均表达量打分,把每个cluster的所有候选marker表达量算出来,以矩阵形式查看。
这一步的核心代码是利用AverageExpression函数:
avg <- AverageExpression(seu, features = all_markers, group.by = "seurat_clusters") avg_mat <- as.matrix(avg$RNA) pheatmap::pheatmap(avg_mat, scale = "row", cluster_cols = FALSE)这一步相当于把“哪个cluster表达哪些marker”变成了一个可量化的热图,判断标准就不只是感觉了。比如某个cluster在CD3D上平均表达高、在CD14上低,那它就比较像T细胞而不是髓系细胞。
如果担心平均表达会把稀疏数据中的噪声也平均进去,可以配合PercentageFeatureSet——计算每个cluster中阳性细胞的比例。比例高又表达量高,才是真正值得采信的marker;表达量高但只有极少数细胞阳性,那更可能是某个小亚群的信号,注释时要留意。
实际上,这个比例判断能帮你减少很多误注释。举例来说,如果一个cluster在某个marker上的平均表达不低,但阳性比例很低,说明这个信号来自很少的细胞,一种可能是该cluster里混入了少量其他类型的细胞,另一种可能是这个marker对应的细胞类型并不是cluster的主流,注释时应该以阳性比例高的其他marker为准。
3.3 第三步:用小提琴图和气泡图做最终确认
平均表达矩阵看完了,对初步注释有数了,但还不能直接定稿。因为平均表达隐藏了单细胞的分布结构,一个marker可能有几个极端高表达的细胞拉高了平均值,而大多数细胞其实是阴性。这时候需要用VlnPlot和DotPlot做最终验证。
VlnPlot(seu, features = c("CD3D", "CD8A", "GZMB"), group.by = "seurat_clusters", pt.size = 0) DotPlot(seu, features = c("CD3D", "CD8A", "GZMB"), group.by = "seurat_clusters")小提琴图重点看表达分布的形状,如果marker阳性信号的峰和阴性信号的峰明显分开,说明这是一个像样的marker;如果阳性细胞零零散散、整体分布跟阴性没有明显差距,那就不要用这个marker支撑注释。
DotPlot则是看两个维度,点的大小表示阳性比例,颜色深浅表示平均表达量。判断标准很直观:一个cluster如果在该marker上既大又红,说明这个marker对它来说是可靠的特征;如果点很小或者颜色很浅,哪怕热图里数值偏高也不能作为主要依据。
这一步之后,我会对每个cluster形成一个明确的注释意见:它是哪种细胞,依据是哪几个marker组合,有没有疑虑。如果某个cluster始终找不到合适的marker说明身份,先不要硬命名,标记为unknown,后面单独处理。
3.4 第四步:处理“注释不上”的细胞群
每个做过单细胞分析的人应该都遇到过那种“什么marker都不明显”的cluster,它在UMAP上孤立存在,表达谱的差异基因又不太能说明身份。针对这种群,我有几个处理建议。
先排除技术因素。检查这个cluster的nFeature、nCount和percent.mt,如果明显偏低,大概率是低质量细胞或空液滴残留,注释为低质量群即可。
然后再排除双细胞可能。用DoubletFinder或scDblFinder看看该cluster的双细胞评分是否偏高,如果高,建议直接用subset去除,避免干扰后续分析。
如果排除技术因素后仍然存在,我倾向于把它当作一类特殊状态来分析,而不是硬性赋予细胞类型标签。有时候这类群代表细胞周期相关的增殖群,检查MKI67、PCNA等增殖marker就能确认;有时候则是应激或干扰素响应引起的转录状态改变,代表性基因比如ISG15、IFI6等。命名时可以直接叫“增殖T细胞”或“干扰素响应细胞”,只要描述的是转录状态而不强行套细胞类型,审稿人也不会质疑。
4. 注释之后不能停:功能分析与验证让注释站得住脚
人工注释的工作如果停留在“画个图、起个名”这一步,其实还远没结束。一个注释结果是否能支撑后续的生物学结论,需要功能分析来验证。更重要的是,功能分析反过来还能验证你的注释是否准确,这是一个双向强化的过程。
4.1 用AddModuleScore做标记基因打分验证
注释完成一个亚群后,我做的第一件事是用AddModuleScore对每个细胞计算该亚群marker基因集的打分,验证注释的可靠性。
seu <- AddModuleScore(seu, features = list(CD8_T_markers), name = "CD8T_score") FeaturePlot(seu, features = "CD8T_score1")这个打分的基本逻辑是:如果一个cluster被注释为CD8阳性T细胞,那么该cluster里的细胞在这个marker基因集上的平均打分应该显著高于其他细胞。如果打分结果和注释不一致——比如被注释为CD8T的cluster在CD8marker打分上并不高——就需要回去重新审视注释了。
我习惯用这个打分结果做两个验证:一是看FeaturePlot上打分高的区域和注释cluster是否重合,二是用箱线图按cluster比较打分分布,确认注释的cluster打分显著更高。这个验证不需要复杂的统计学方法,直观可视化就足够判断。
4.2 用GSVA或GSEA看通路富集差异
注释完亚群后,一个常见问题是:你这个亚群在功能上有什么特别之处?单纯列marker基因是不够的,审稿人会进一步追问这些基因富集在哪些通路里。这时候通路富集分析就很关键。
对于单细胞数据,我通常不用最朴素的GO分析,因为单细胞表达矩阵稀疏性太强,直接做差异基因富集容易受dropout影响。我比较推荐用GSVA或AUCell这类基于基因集打分的算法,先把单个细胞的通路活性算出来,再做组间比较,稳健性会好很多。
library(GSVA) gsva_res <- gsva(expr_mat, gene_sets, method = "ssgsea")分析思路也很直接:选定几个你关注的生物学通路或基因集,比如炎症反应、糖酵解、氧化磷酸化、凋亡等,比较不同亚群在这些通路上的活性差异。如果注释为调节性T细胞的亚群在TGF-β信号通路上显著富集,这就能从功能层面支持注释结果。如果注释的某个亚群功能特征和它应有的角色完全矛盾,那就需要警惕注释可能出了问题。
4.3 细胞通讯分析让注释更有生物学意义
单细胞分析做到后面,多数人会在注释结果上再加一步细胞通讯分析。最常用的工具是CellChat和CellPhoneDB,这类分析可以从配体受体层面解释不同细胞亚群之间如何相互作用。
这一步对注释的验证作用是隐性的:如果注释的细胞类型在通讯网络中显示出符合预期的相互作用关系,比如巨噬细胞和T细胞之间存在趋化因子受体配体对,那说明注释的细胞类型在生物学语境下是自洽的。反之,如果某类细胞被注释得跟正常生理关系完全格格不入,就需要重新考虑注释了。
做细胞通讯分析时注意一个事项:不是所有亚群都适合纳入分析,建议先在较大群体层面(比如CD4T、CD8T、巨噬细胞、B细胞、NK细胞等)运行,看主要信号关系是否合理,然后再针对感兴趣的亚群做细分层面的通讯分析。如果一开始就堆了几十个亚群,结果图会乱得根本读不出来,反而影响了判断。
4.4 复核差异marker与文献一致性
功能分析跑完,我最后一步是回到最基础的差异表达结果上,把每个注释亚群的top差异基因完整过一遍,和文献对比确认一致性。
这一步是我雷打不动的习惯。具体来说,我会用FindAllMarkers重新跑一遍注释后的亚群之间差异基因,只保留avg_log2FC > 0.5且p_val_adj < 0.05的基因,然后逐个亚群看top20的基因列表。对照已知文献,每个亚群是否表达对应的核心转录因子和表面标志物,能不能讲出一个合理的故事。
这个复核看起来简单,但能筛出不少问题。我印象最深的一次是有一个亚群的top markers列表确实符合某个细胞类型,但仔细看发现关键转录因子表达水平其实很低,反而另一个不那么出名的转录因子表达很高。查文献后确认,这个亚群实际上是一个更罕见的状态,重新注释之后整个后续分析逻辑都顺了很多。人工注释本质上是一个需要不断回头修正的过程,而不是一次性搞定。
5. 常见问题与排查技巧实录
人工注释做到一定量以后,遇到问题反而是常态。这一节我把平时踩过的坑和排查经验整理成速查表,希望能省掉大家一些弯路。
5.1 常见问题速查表
| 问题现象 | 可能原因 | 排查与处理方法 |
|---|---|---|
| cluster没有明显marker | 低质量细胞/空液滴 | 检查nFeature和percent.mt,确认后直接剔除 |
| cluster同时表达多种谱系marker | 双细胞 | 用DoubletFinder识别并移除 |
| 同一细胞类型被拆成多个cluster | 聚类过度(分辨率过高) | 适当降低分辨率后重新聚类 |
| 不同样本相同细胞类型没有聚在一起 | 批次效应 | 使用Harmony/CCA整合后再聚类 |
| 注释结果与SingleR结果差异大 | 参考数据集不匹配 | 重新确认marker表达,以数据本身为准 |
| marker表达量低但cluster明显 | 测序深度不足或dropout | 同时查看阳性比例和表达分布,避免单看平均表达 |
5.2 两个高频“翻车”场景复盘
场景一:无辜的干扰素响应群
我第一次独立做一批外周血单细胞数据时,发现有一个cluster同时高表达所有干扰素刺激基因,ISG15、IFI6、MX1、OAS1全都在。当时第一反应是找这个群的细胞类型marker,结果什么经典marker都是阴性的,愣是注释不出来。后来才知道这就是典型的干扰素响应状态,这种转录状态会覆盖原本的细胞身份信号,让细胞看起来像是失去特征了。
处理办法是先用GetAssayData检查ISG基因在这群细胞的表达,确认是高表达,然后在注释时直接命名为“ISG阳性细胞群”,在后续分析中要么单独讨论要么在功能分析前先排除,否则会干扰其他亚群的信号。
场景二:强行命名的代价
还有一次我把一群注释成了某个罕见的T细胞亚群,图看起来一切都对,因为marker确实表达了。但进一步做拟时序分析时,这个群的定位跟生物学常识完全对不上,回头一查才发现这个亚群其实是细胞周期S期的T细胞,我用的那些“marker”恰好是细胞周期相关基因。从那以后,我每次注释前都会先把MKI67、TOP2A、PCNA等增殖marker检查一遍,避免把周期信号当成细胞身份信号。强烈建议你在注释前养成这个习惯。
5.3 批量样本注释的一致性维护
如果你手头的数据来自多个样本或者多个条件下批量注释,一个容易被忽视的问题是不同批次注释标准不一致。比如一批数据里你把某个细胞群叫“CD8阳性效应T细胞”,另一批数据里同样的群却叫“效应记忆T细胞”。这种情况在多人协同时尤其常见,同一张UMAP图,不同人注释出来的版本经常完全不一样。
我的解决方案是,在项目开始前统一制定一套注释规范:明确使用哪些marker组合定义每一类细胞、每个细胞类型的筛选条件是什么、标记为unknown的标准是什么。然后所有样本使用同一套脚本、同一份marker列表做注释,避免个人主观造成的差异。给每个亚群注释附上一句文字说明,标记依据哪几个marker和哪些文献,这样即使过段时间回头检查,也能快速回忆起当时做判断的思路。
这套方法虽然看起来费时间,但长期做下来反而最省心。尤其在准备论文方法学部分时,你会有充足的描述材料支撑注释依据,审稿人也更容易信服。
个人经验收尾
做了不少单细胞注释项目之后,我的体会是人工注释本质上不是在“识别”细胞类型,而是在“论证”细胞类型。每一个命名都应该有数据支撑、有文献支撑、有逻辑支撑,经得起追问。这个过程的诀窍不在于掌握高深算法,而在于耐心和细致:一遍遍验证marker表达情况,把看起来正确的结论反复放到功能分析里去检验。花在这个环节上的时间永远不会白费,因为它决定了你后续所有分析的生物学可信度,也决定了审稿人对你方法和结果的第一印象。希望这篇流程能帮你把人工注释这个环节做得扎实又心安,最后再分享一个小技巧:注释过程中随时保存每个cluster的marker查看记录和判断理由,你会发现最后写论文方法部分时,这套记录简直是无价之宝。