做单细胞转录组的人,多少都碰过这样的场景:一批数据下来,标准化、降维、聚类都跑完了,结果到了注释细胞类型这一步,全靠手动翻Marker基因,眼睛都快看花了。尤其当样本来自大脑这种细胞组成极其复杂的组织,一个cluster一个cluster地核对标记基因,效率低不说,还容易在抑制性神经元和兴奋性神经元之间反复纠结。如果你也在这个环节上耗过时间,那Allen Institute开源的scrattch这个R包,值得好好了解一下。
scrattch(single cell RNA-seq analysis tools for cell type characterization)是艾伦脑科学研究所(Allen Institute for Brain Science)在GitHub上维护的一套单细胞RNA测序分析工具集,最初是为了支撑他们自己的脑细胞类型图谱项目而开发的。它解决的痛点非常明确:在大型单细胞数据集上,高效地完成聚类、差异表达分析、细胞类型注释和分类映射,并提供一套可复现、可扩展的工作流。适合做脑科学、神经科学、以及各类需要精细细胞类型鉴定的单细胞研究组参考使用。
接下来我从项目设计、核心功能、实操流程和踩坑经验四个维度来聊聊我对scrattch的理解。不是官方文档的复述,是我在真实数据集上跑过之后的一些体会。
1. 项目背景与核心定位:为什么单细胞分析需要scrattch
1.1 从脑科学数据到通用工具
scrattch不是那种一上来就想着"做一个大家都用的包"的项目。它最开始服务的是Allen Institute自己的脑细胞图谱计划,这类项目的共同特点是:样本量大、细胞数量大、注释要求精细。大脑组织的复杂度在哺乳动物里是天花板级别的,兴奋性神经元、抑制性神经元、各种胶质细胞、血管内皮细胞、免疫细胞混在一起,亚型之间往往只有几个基因的表达差异。用通用流程跑完聚类,得到的只是一堆数字编号的cluster,要把这些cluster翻译成有生物学意义的细胞类型,需要一套专门设计的工具链。
scrattch这个包就是在这样的需求下长出来的。它跟常见的单细胞分析包最大的不同在于:它不只是做降维聚类,而是更关注"聚完类之后怎么办"。项目核心思路是把细胞类型鉴定这件事拆成几个环节:数据整理、差异表达、层级关系构建、分类器训练、结果可视化。每个环节都有对应的工具支撑,并且彼此之间衔接顺畅。这也是为什么很多实验室在构建自己的细胞图谱时会直接拿scrattch作为底子。
1.2 scrattch能做什么、不能做什么
先说能做什么。它擅长在大规模数据上做细胞类型的系统化注释。比如你有一批来自多个个体的皮层样本,跑完Seurat聚类之后得到40个cluster,scrattch可以帮你做几件非常实际的事情:计算cluster之间的表达相似度,构建一棵细胞类型的层级树;找出每个cluster的特异性标记基因;训练一个分类器,让你后续的新数据可以直接映射到这个注释体系里。这套流程一旦跑通,后续所有新增数据都不需要重新手动注释,节省的时间是肉眼可见的。
再说不能做什么。scrattch不是零基础入门工具,它不会替你做质量控制,也不包含完整的标准化流程,更不是一键出图的傻瓜软件。它默认你已经有基本的R语言功底,并且对单细胞分析的基本概念——如UMAP、聚类分辨率、批次效应——有一定理解。如果你是第一次接触单细胞数据,建议先用Seurat官方教程跑通一遍基础流程,再来看scrattch。否则大概率会在环境配置阶段就卡住,反而体会不到这个工具的好处。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术拆解:scrattch设计里的几个关键思路
2.1 从矩阵到h5ad的数据层设计
scrattch在数据层做了比较务实的处理。单细胞数据动辄几万细胞乘以几万基因,在R里直接以普通矩阵形式存储,内存压力非常大。scrattch的设计里大量使用了HDF5格式,尤其是与Python生态中广泛使用的h5ad文件格式做了对接。很多时候你在R里分析到一半,发现某个步骤在Python的scanpy里更高效,需要把Seurat对象导出成h5ad,再在Python里处理,然后再导回来。scrattch提供了R与h5ad之间互转的接口,整个过程不需要把数据重新读一遍文本文件,既省内存又省时间。
我个人的习惯是:上游的原始数据整理在R里做,聚类后用scrattch导出h5ad,到Python里跑一些深度学习相关的聚类和批次整合,再将结果导回R做注释。这个流程在之前需要手动写一堆数据转换代码,有了scrattch之后,数据转换变成了函数级操作,出错概率直线下降。
2.2 细胞类型层级与树状结构
这是我认为scrattch最有价值的设计之一。常见的聚类结果是扁平化的:cluster 0到cluster 39,彼此之间看不出关系。但生物学上,这些cluster不是孤立的。举个例子,你可能有5个cluster都表达Sst(生长抑素),它们属于抑制性神经元这个大类的不同亚型;另外7个cluster可能都属于兴奋性神经元。扁平结果无法直观展示这种层级关系,而scrattch会基于聚类之间的表达相关性构建树状结构,让你能一眼看出哪些cluster在转录组层面更接近,哪些更远。
这个设计对注释的意义非常大。你在看扁平cluster时,面对的是40个彼此等价的数字;但在树状图里,你面对的是一个有结构、有层次的系统。注释时可以先确定大类的边界,再在亚型层面细分,逻辑上顺畅很多。实际使用中,我会先看树状图,找出几个明显的大分支,然后针对每个分支内部的小簇做精细注释,思路比之前清晰不少。
2.3 分类器与跨数据集映射
一个细胞类型注释体系的价值,不仅体现在当前数据集上,还体现在它能不能延伸到未来的数据上。scrattch在这一点上做得很到位:它允许你基于已经注释好的数据集训练分类器,然后把新的、未注释的数据映射到这个参考体系里。这在多批次、多样本、多研究中心的项目中是刚需。
做法上大致是:用已注释的数据作为训练集,每个cluster的转录组特征作为参考,然后对新数据的每个细胞进行计算,判断它最接近哪个已知类型。我自己做过一次跨物种映射实验,效果虽然不能说完美,但准确率在主要细胞大类上非常可观。当然,这个功能也有它的局限性,我后面在常见问题里会详细说。
2.4 可视化与交互式探索
scrattch在可视化上的思路也不一样。常规的UMAP图、tSNE图当然能出,但它更强调交互式探索。它提供了一些交互式浏览的组件,让用户能在二维投影上放大、选中、高亮,结合基因表达量去查看某个细胞群的特征。尤其在标注阶段,我经常在一个图里同时打开UMAP和基因表达热图,点击一个区域,立刻看这个区域里的细胞在关键标记基因上的表达情况。这种交互式的工作流比反复改代码、重出图高效太多。
对于科研团队来说,这种交互式的产物还有一个间接好处:便于组内讨论。你不需要让每个人都会跑代码,打开一个交互式界面就能浏览数据,这在课题组分工明确、成员背景多元的情况下非常实用。
3. 实操流程:从读入数据到输出细胞类型注释
3.1 环境准备与依赖安装
先说安装。scrattch是R包,依赖不少,建议在干净的R环境里安装。我使用的R版本是4.3.x,Bioconductor 3.18,整体兼容性没有问题。安装代码如下:
r复制if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install(c("SingleCellExperiment", "scater", "scran"))
# 安装核心包
if (!requireNamespace("devtools", quietly = TRUE))
install.packages("devtools")
devtools::install_github("AllenInstitute/scrattch")
这里特别提醒一句:不要跳过Bioconductor依赖直接装scrattch。它内部很多函数依赖SingleCellExperiment这套数据结构,如果依赖没装全,编译时会报一堆找不到头文件的错误,排查起来非常浪费时间。我踩过一次坑,后来学聪明了,凡是GitHub上的R包,第一步永远是先把Bioconductor依赖列表清一遍。
3.2 数据导入与质量控制
scrattch本身不自带完整QC流程,所以我的做法是:先用Seurat完成标准QC和预处理,再接入scrattch。QC阶段我比较关注的指标包括:每个细胞的基因数、UMI总数、线粒体基因比例。基因数过低说明细胞可能已经破裂,过高则可能是双细胞,线粒体比例高通常提示细胞状态不佳。
r复制library(Seurat)
library(scrattch)
# 读取10x数据
data <- Read10X(data.dir = "filtered_feature_bc_matrix")
obj <- CreateSeuratObject(counts = data, project = "brain")
obj[["percent.mt"]] <- PercentageFeatureSet(obj, pattern = "^MT-")
# 常规过滤标准,具体阈值需要根据组织类型调整
obj <- subset(obj, subset = nFeature_RNA > 500 & nFeature_RNA < 6000 & percent.mt < 10)
这个阶段我没有用scrattch,原因是它把精力集中在细胞类型鉴定上,QC还是Seurat生态更成熟。但预处理完的数据会整理成SingleCellExperiment对象,这一步是为后续scrattch操作做铺垫。
3.3 降维聚类与批次效应处理
预处理完就是标准流程:NormalizeData、FindVariableFeatures、ScaleData、RunPCA、RunUMAP,然后聚类。对于单批次数据,这个流程没有任何问题;但如果数据来自多个样本或者多个批次,我强烈建议在PCA之后做一步批次整合。我自己用的是Harmony,整合效果稳定,而且可以直接在Seurat的流程里调用。
r复制obj <- NormalizeData(obj)
obj <- FindVariableFeatures(obj, nfeatures = 3000)
obj <- ScaleData(obj)
obj <- RunPCA(obj, npcs = 50)
obj <- RunHarmony(obj, group.by.vars = "sample_id")
obj <- FindNeighbors(obj, reduction = "harmony", dims = 1:30)
obj <- FindClusters(obj, resolution = 0.8)
obj <- RunUMAP(obj, reduction = "harmony", dims = 1:30)
为什么用Harmony而不是直接简单合并?我在一个来自6个供体的皮层样本数据上做过对比,不整合的话,UMAP图上细胞不会按照类型聚在一起,而是按照供体来源分开,这在后续注释中会造成严重的误导。批次效应是单细胞分析里躲不开的问题,越早处理,后面注释越省心。
3.4 差异表达与标记基因识别
聚类完成后,scrattch的活儿就开始了。第一步是寻找每个cluster的标记基因。这里我通常会用Seurat的FindAllMarkers,这个函数足够稳定,输出结果也可以直接对接scrattch的注释流程。
r复制markers <- FindAllMarkers(obj, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.5)
拿到标记基因表之后,不要直接按logFC排序就开始注释。我的习惯是,把每个cluster的Top 20标记基因和已知的细胞类型标记基因表做交叉比对。大脑组织里常用的标记基因就那些:Pvalb、Sst、Vip对应抑制性神经元亚型,Slc17a7(VGLUT1)是皮层兴奋性神经元的标志,Aqp4是星形胶质细胞,Mbp是少突胶质细胞,Cx3cr1是小胶质细胞。如果某个cluster的标记基因同时出现Pvalb和大量的神经递质相关基因,这个cluster大概率是抑制性神经元。
3.5 树状图构建与注释
标记基因都看完了,接下来就是scrattch的核心环节:基于cluster间的转录组相似度构建树状结构,辅助系统化注释。这套逻辑类似于对cluster做一次层次聚类,但实现上针对单细胞数据的特点做了优化,速度很快。
我在实际操作中拿到树状图后,会按以下几个顺序来注释:
- 先定大类。树状图最上层的分支,基本上对应神经元、星形胶质、少突胶质、小胶质这些大类。
- 再细分神经元亚类。每个神经元大分支下面,再根据Pvalb、Sst、Vip等成熟标记基因区分亚型。
- 最后处理边界模糊的小簇。如果某个小簇在树状图上的位置游移不定,标记基因也不明确,我会把它暂时标记为"未知",而不是强行注释成一个已知类型。
这套方法的优点是:注释是"自上而下"的,每一步都有依据。不像手动看扁平cluster那样,注释完全依赖个人经验,结果也难以复现。
3.6 用分类器验证注释结果
注释完成不代表结束,我强烈建议基于注释结果训练一个分类器,然后用交叉验证来检验注释的可靠性。scrattch的分类器功能可以做到这一点:用一部分细胞训练分类器,然后用它来预测剩下细胞的类型,看准确率是否稳定。
这个环节还有一个附加好处:训练好的分类器可以直接用于新数据的映射。如果后期续测了一批新样本,不需要重新聚类和手动注释,直接调用分类器,把新细胞映射到已有的注释体系里,整个过程几分钟就能完成。对一个长期项目来说,这个能力极大降低了下游分析的人工成本。
4. 常见问题与排查技巧实录
4.1 安装阶段的依赖地狱
这是反映最多的一个问题。scrattch的依赖涉及R基础包、Bioconductor包和部分GitHub依赖包,错一个就装不上。最典型的报错是缺少系统级的编译工具,比如在Linux服务器上缺少gfortran或者libcurl,在Mac上缺少Xcode Command Line Tools。排查思路是先看报错发生在哪个包的编译阶段,然后针对性安装对应的系统依赖。装不上时可以先试试安装一个精简版本,比如只装scrattch而跳过可视化相关的依赖,后续用到哪个功能再补哪个。
4.2 大规模数据的内存和速度问题
单细胞数据一大,内存和速度就变得很敏感。我的经验是,如果细胞数量超过20万,尽量用HDF5格式存储数据,不要全量加载进内存。scrattch对h5ad的支持正好解决了这个问题。第一次处理25万细胞的数据时我吃过亏,直接全量载入导致服务器内存爆满,后来改成流式读取,再配合矩阵的稀疏格式,问题就解决了。另外,在R里操作大型稀疏矩阵时,尽量使用Matrix包提供的稀疏矩阵类型,避免将数据转成普通的稠密矩阵。
4.3 聚类不稳定、注释主观性强怎么办
聚类结果受分辨率参数影响很大。同一个数据集,resolution设0.5和1.2得到的结果可能差别很大。我的做法是多次用不同分辨率跑聚类,然后观察哪些cluster在多个分辨率下都稳定出现,这些cluster才是可靠的注释单元;那些只在某个特定分辨率下出现的小簇,注释时要格外谨慎。此外,如果可能,用两个不同的聚类算法做交叉验证,取交集来定义核心细胞类型,这样注释结果会扎实很多。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 解决思路 |
|---|---|---|
| 安装时编译报错 | 缺少系统级依赖 | 根据报错定位依赖包,安装对应编译工具 |
| 内存不足 | 全量加载稀疏矩阵为稠密 | 使用HDF5存储,保持稀疏格式 |
| 聚类结果每次不一样 | 部分聚类算法随机性 | 设置随机种子,多次聚类取稳定核心簇 |
| 新数据映射准确率低 | 参考数据与新数据存在较大批次/物种差异 | 用Harmony等工具整合之后再做映射 |
| 标记基因不明显 | 聚类分辨率过高,切割过细 | 降低resolution重新聚类,或合并相似cluster |
5. 我的几点实操体会
项目跑得多了,最深的感受是:细胞类型注释这件事,工具只能帮你提高效率和规范性,最终的生物学判断还是得靠人。scrattch的价值在于,它把"整理数据、计算差异、构建层级、训练分类器"这些重复劳动变成标准的、可复现的流程,让人把精力放到真正需要判断力的地方。我到现在还记得第一次用树状图取代扁平cluster做注释的那天,原来需要一个星期的注释工作,缩短到一天不到,而且结果更有序、更经得起推敲。
最后再分享一个小技巧:如果你想在自己项目里引入scrattch,不要一开始就在完整数据上硬跑。先用一个有代表性的子集,比如每个样本抽几百个细胞,把整个工作流在子集上跑通,确认每个环节的输出格式和参数都符合预期后,再放到全量数据上。这个习惯帮我避开了很多因参数设置不当而浪费算力的坑。后续如果需要扩展,可以试试把scrattch与更细的标记基因数据库、空间转录组数据结合起来做联合注释,这条路我觉得还有很大的想象空间。
