单细胞质控三指标怎么设阈值
跟完这篇,您能针对自己的单细胞数据,看着分布把 nFeature_RNA、nCount_RNA、线粒体比例三条质控线定下来,滤掉低质量细胞和双细胞,又不至于把真实细胞群一起滤掉。
单细胞下游的聚类、注释、差异,都建立在「留下来的每个细胞都是一个健康的、单个的细胞」这个前提上。质控就是把不满足这个前提的液滴挑出去。整篇按这条线走:
- 读入数据,算出三个质控指标(含线粒体比例);
- 画分布图,看着自己的分布定三条阈值线;
- 用专门方法补处理双细胞与空液滴;
- 过滤,再回头检查有没有滤过头。
三个指标各反映什么
先弄清这三个数分别在说什么,才谈得上怎么卡:
| 指标 | 含义 | 太低说明 | 太高说明 |
|---|---|---|---|
| nFeature_RNA | 这个细胞里检测到的基因数 | 空液滴、破损细胞、低质量 | 疑似双细胞(两个细胞挤进一个液滴) |
| nCount_RNA | 这个细胞里的 UMI 总数(总转录本数) | 建库效率低、细胞将死 | 疑似双细胞或超大细胞 |
| percent.mt | 线粒体基因占总表达的百分比 | —— | 细胞膜破裂、胞质 mRNA 漏出、细胞将死 |
三者背后其实是同一件事的不同侧面:
- nFeature_RNA 和 nCount_RNA 高度相关,一般一起看。两头都要留意:太低多半是没装进完整细胞,太高常是一个液滴里裹了两个细胞。
- 线粒体比例是「细胞死没死」的信号灯。细胞破裂时,胞质里的 mRNA 先漏出去,线粒体因为有膜包着相对留存,于是线粒体转录本的占比被动升高。所以线粒体比例高,通常代表这是个正在死亡或已受损的细胞。
读入数据、把线粒体比例算出来
nFeature_RNA 和 nCount_RNA 在 Seurat 建对象时会自动算好,线粒体比例要自己按基因名前缀统计。先把矩阵读进来、建立对象:
library(Seurat)
# 读入 10x 的三件套(barcodes / features / matrix 同放一个目录)
counts <- Read10X(data.dir = "filtered_feature_bc_matrix/")
# 若拿到的是 .h5,改用 Read10X_h5("filtered_feature_bc_matrix.h5")
# 建对象时先做一道最粗的过滤:
# min.cells —— 基因至少在这么多细胞里出现,才保留
# min.features —— 细胞至少测到这么多基因,才保留
# 3 和 200 是 Seurat 教程常用起点,属于惯例,按数据调、不是铁律
seu <- CreateSeuratObject(
counts = counts,
project = "my_sample",
min.cells = 3,
min.features = 200
)
再按基因名前缀算线粒体比例。人类线粒体基因以 MT- 开头,小鼠是 mt-,别搞混物种:
# 人类:以 MT- 开头的基因即线粒体基因
seu[["percent.mt"]] <- PercentageFeatureSet(seu, pattern = "^MT-")
# 小鼠请改成小写前缀
# seu[["percent.mt"]] <- PercentageFeatureSet(seu, pattern = "^mt-")
算完 percent.mt 会作为一列存进对象的 meta.data,和 nFeature_RNA、nCount_RNA 并列,后面一起看分布、一起做过滤。
提示:如果画出来
percent.mt几乎全是 0,多半是前缀写错了(物种不对,或参考基因组里线粒体基因用了别的命名)。先回去核对基因名,别急着往下走。
看分布、按分布定阈值
**最关键的一条:阈值要看着自己数据的分布定,不要照抄别人教程里的数字。**同样是「线粒体 < 10%」,放在 PBMC 上很合理,放在心肌、肝脏这类线粒体本就丰富的组织上就会把好细胞误杀。做法是先画三张小提琴图,看清分布再下刀:
VlnPlot(seu,
features = c("nFeature_RNA", "nCount_RNA", "percent.mt"),
ncol = 3, pt.size = 0)
# 配合散点图看两两关系,帮助判断上界
FeatureScatter(seu, "nCount_RNA", "percent.mt")
FeatureScatter(seu, "nCount_RNA", "nFeature_RNA")
看图时按这个思路找拐点:
- 主群体在哪:小提琴的「肚子」是绝大多数正常细胞所在区间,阈值应落在肚子之外的稀疏尾巴上,而不是切进主群体。
- 下界(去空液滴、碎片):nFeature_RNA 在低端往往有一小撮离群点,把它们和主群分开的那条缝,就是下界的候选位置。
- 上界(防双细胞):nFeature_RNA / nCount_RNA 特别高的一小撮,疑似双细胞。上界可以先松一点,把真正的双细胞交给下一节的专门方法处理,避免误伤真实的大细胞。
- 线粒体上界:看
percent.mt小提琴的主群体延伸到哪,再往上留一点余量设界。
一组常被引用的起点值(源自 Seurat 官方 PBMC 教程,仅供参照,不是标准答案):
| 指标 | PBMC 教程用的起点 | 说明 |
|---|---|---|
| nFeature_RNA 下界 | > 200 | 低于此多为空液滴 / 碎片 |
| nFeature_RNA 上界 | < 2500 | 仅 PBMC 情形,别硬套 |
| percent.mt 上界 | < 5 | 免疫细胞可用,其它组织常需放宽 |
这些都是常用惯例、不是铁律。线粒体阈值尤其要因组织而异——同一条 < 10% 换个组织就可能太严或太松:
| 组织 / 样本类型 | 线粒体比例常用上界 | 为什么 |
|---|---|---|
| PBMC、外周血免疫细胞 | < 5%〜10% | 代谢平缓,线粒体占比本就低 |
| 多数培养细胞系、常规实体组织 | < 10%〜20% | 折中区间,看尾巴切 |
| 心肌、骨骼肌、肝、肾 | < 20% 甚至更高 | 线粒体天生丰富,卡太严会误杀好细胞 |
单核 vs 单细胞、新鲜 vs 冻存样本也会整体平移分布,同一套阈值未必能跨样本通用。一个稳妥的习惯:阈值大致在看分布时定好就别反复微调到「结果好看」,并把最终数字写进方法学,保证可复现。
处理双细胞与空液滴
nFeature 的上界只能挡住最粗的双细胞。下面两类问题需要专门的方法,别指望三条阈值线包办。
双细胞(doublet)——两个细胞进了同一个液滴,被当成一个「表达谱混合」的细胞,容易在聚类里冒充「中间态」新群,是假发现的高发来源。常用工具的共同思路都是:造一批人工双细胞当参照,再看每个真实细胞长得有多像双细胞。
| 工具 | 语言 | 特点 |
|---|---|---|
| DoubletFinder | R | 与 Seurat 流程衔接顺,需先扫 pK 参数 |
| scDblFinder | R(Bioconductor) | 较新、较快,一步打分 |
| Scrublet | Python | scanpy 生态常用 |
这类方法要在标准降维聚类跑完之后做:
# 前置:NormalizeData → FindVariableFeatures → ScaleData →
# RunPCA → RunUMAP → FindClusters 已跑完
library(DoubletFinder)
# 预期双细胞数 = 双细胞率 × 细胞数
# 10x 的经验规律:装载越多,双细胞率越高(约每千个细胞增加不到 1%),
# 具体比率请以试剂 / 仪器说明为准
nExp <- round(0.075 * ncol(seu)) # 例:约 7.5%,按实际细胞数换算
DoubletFinder 还需要先用
paramSweep系列函数扫出最优pK再正式运行,且函数名(是否带_v3后缀)随包版本变化。这里只给到思路和关键参数,具体调用请对照您所装版本的官方文档,不要照抄固定的函数签名。
空液滴(empty droplet)——液滴里没有细胞、只有环境游离 RNA(ambient RNA)。如果您用的是 CellRanger 输出的 filtered 矩阵,这一步 CellRanger 已经替您做过初筛;若从 raw(未过滤)矩阵起步,可用 DropletUtils 包的 emptyDrops() 区分真细胞与空液滴。环境 RNA 的污染另有 SoupX、DecontX 等工具校正,属于进阶步骤,按需再引入。
过滤,并检查有没有滤过头
阈值定好后用一行 subset() 过滤。三条线用 & 串起来(下面的数字只是示例,请换成您自己看分布定的值):
seu.filt <- subset(
seu,
subset = nFeature_RNA > 200 &
nFeature_RNA < 2500 &
percent.mt < 10
)
**过滤最怕滤过头——把某个真实细胞群整片切掉却不自知。**过滤完一定要回头对一次账:
-
看留了多少:细胞数掉太多要警惕。
ncol(seu) # 过滤前 ncol(seu.filt) # 过滤后 -
重画小提琴图:确认尾巴被切掉、主群体完好无损。
VlnPlot(seu.filt, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3, pt.size = 0) -
分样本、分群体核对损耗是否均匀:如果某一个样本或某一群细胞被过滤掉了大半,往往不是「它们都是坏细胞」,而是阈值对这部分太严——比如把一个线粒体天然偏高的细胞类型整片误杀。这种不均匀的损耗,是需要回头放宽阈值的信号。
判断标准没有统一数字,但可以记住方向:宁可先松一点、多留一些边缘细胞,也别一刀切得太狠——低质量细胞在后续聚类里通常会自成一群、容易识别,而被误删的真实细胞群则再也找不回来了。过滤是可以迭代的:看完聚类结果,若发现某群明显是残余低质量细胞,再回来收紧对应指标即可。
在平台上跑一遍
在百沐一下做这一步不用写代码:上传单细胞矩阵后,平台会自动算好 nFeature_RNA、nCount_RNA 与线粒体比例,画出三张分布图供您看着定阈值,并给出双细胞检测;您只需说清组织类型和大致意图,它会把过滤前后的细胞数与分布一并列出来让您确认没有滤过头。到 https://app.baimuyixia.com 传一份数据就能试跑,也可先看 组学智能体怎么用 了解交互方式。
相关
- 单细胞分析全流程 —— 从质控到聚类注释的主线导航
- 降维聚类:PCA / UMAP 参数怎么调 —— 质控之后的下一步
- 表达矩阵与分组表整理规范 —— 矩阵长什么样、样本名怎么对齐
- 上传数据的格式要求 —— 单细胞各类输入文件的格式说明