180_单细胞doublet检测¶
一句话概述¶
单细胞测序中的doublet是指两个或多个细胞被错误地标记为同一个细胞(共享同一个barcode),通过计算方法(如Scrublet、DoubletFinder、scDblFinder)检测并移除doublet是单细胞数据质控的关键步骤。
核心知识点表格¶
| 知识点 | 说明 |
|---|---|
| Doublet定义 | 两个细胞共享一个液滴/barcode产生的混合表达谱 |
| Doublet类型 | 同型doublet(同类型细胞)和异型doublet(不同类型细胞) |
| 预期doublet率 | 约0.8%每1000个细胞(10x Chromium) |
| 检测原理 | 人工模拟doublet,检测与模拟doublet相似的真实细胞 |
| 常用工具 | Scrublet(Python)、DoubletFinder(R)、scDblFinder(R) |
| 同型doublet | 难以检测,因表达谱与正常细胞相似 |
| 多样本策略 | 基于SNP的demuxlet方法可物理鉴定doublet |
| 过滤标准 | 通常移除预测的doublet,而非仅标记 |
步骤详解¶
第一步:理解doublet的产生与影响¶
白话解释:10x等微液滴平台中,偶尔会有两个细胞掉进同一个液滴里,产生混合的表达数据。这些"双细胞"如果不去除,会在聚类分析中创建虚假的中间细胞类型。
技术细节:doublet率与加载细胞数近似呈线性关系。10x平台标称doublet率约每1000细胞0.8%(即加载10000细胞,预期约800个doublet,8%)。异型doublet(来自不同类型的细胞)在降维空间中通常位于两个cluster之间,更容易检测;同型doublet(来自同一类型)几乎无法通过计算方法检测。
第二步:使用Scrublet检测(Python)¶
白话解释:Scrublet是最流行的Python doublet检测工具。它通过随机配对真实细胞来模拟doublet,然后找出哪些真实细胞的表达谱与模拟doublet相似。
import scrublet as scr
import scanpy as sc
import numpy as np
import matplotlib.pyplot as plt
# 加载数据
adata = sc.read_10x_h5("filtered_feature_bc_matrix.h5")
# 运行Scrublet
scrub = scr.Scrublet(adata.X, expected_doublet_rate=0.06)
doublet_scores, predicted_doublets = scrub.scrub_doublets(
min_counts=2,
min_cells=3,
min_gene_variability_pctl=85,
n_prin_comps=30
)
# 查看结果
print(f"检测到的doublet数: {sum(predicted_doublets)}")
print(f"Doublet比例: {sum(predicted_doublets)/len(predicted_doublets)*100:.1f}%")
# 可视化doublet分数分布
scrub.plot_histogram()
plt.savefig("scrublet_histogram.png", dpi=300)
# 将结果添加到adata
adata.obs['doublet_score'] = doublet_scores
adata.obs['predicted_doublet'] = predicted_doublets
# 如果自动阈值不合适,手动调整
# scrub.call_doublets(threshold=0.25)
# UMAP上展示doublet
sc.pp.normalize_total(adata)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata)
sc.tl.pca(adata)
sc.pp.neighbors(adata)
sc.tl.umap(adata)
sc.pl.umap(adata, color=['doublet_score', 'predicted_doublet'],
save='_doublets.png')
# 过滤doublet
adata_clean = adata[~adata.obs['predicted_doublet']].copy()
print(f"过滤前: {adata.n_obs} cells, 过滤后: {adata_clean.n_obs} cells")
第三步:使用DoubletFinder检测(R/Seurat)¶
白话解释:DoubletFinder是Seurat生态中最流行的doublet检测R包。它的方法类似Scrublet但有一些独特的参数需要优化。
library(Seurat)
library(DoubletFinder)
# 加载并预处理数据
pbmc <- Read10X(data.dir = "filtered_feature_bc_matrix/")
pbmc <- CreateSeuratObject(counts = pbmc, min.cells = 3, min.features = 200)
pbmc <- NormalizeData(pbmc)
pbmc <- FindVariableFeatures(pbmc, selection.method = "vst", nfeatures = 2000)
pbmc <- ScaleData(pbmc)
pbmc <- RunPCA(pbmc)
pbmc <- RunUMAP(pbmc, dims = 1:20)
pbmc <- FindNeighbors(pbmc, dims = 1:20)
pbmc <- FindClusters(pbmc, resolution = 0.5)
# Step1: 优化pK参数
sweep.res <- paramSweep(pbmc, PCs = 1:20, sct = FALSE)
sweep.stats <- summarizeSweep(sweep.res, GT = FALSE)
bcmvn <- find.pK(sweep.stats)
# 选择最优pK
optimal_pk <- as.numeric(as.character(bcmvn$pK[which.max(bcmvn$BCmetric)]))
cat("Optimal pK:", optimal_pk, "\n")
# Step2: 估计同型doublet比例
homotypic.prop <- modelHomotypic(pbmc$seurat_clusters)
nExp_poi <- round(0.08 * nrow(pbmc@meta.data)) # 假设8% doublet率
nExp_poi.adj <- round(nExp_poi * (1 - homotypic.prop))
# Step3: 运行DoubletFinder
pbmc <- doubletFinder(
pbmc,
PCs = 1:20,
pN = 0.25,
pK = optimal_pk,
nExp = nExp_poi.adj,
sct = FALSE
)
# 查看结果
df_col <- grep("DF.classifications", colnames(pbmc@meta.data), value = TRUE)
table(pbmc@meta.data[[df_col]])
# 可视化
DimPlot(pbmc, group.by = df_col, cols = c("Singlet" = "grey", "Doublet" = "red"))
# 过滤doublet
pbmc_clean <- subset(pbmc, cells = colnames(pbmc)[pbmc@meta.data[[df_col]] == "Singlet"])
第四步:使用scDblFinder(推荐,速度快)¶
白话解释:scDblFinder是较新的doublet检测工具,在多个benchmark中表现最好,而且速度最快。推荐作为首选方法。
library(scDblFinder)
library(SingleCellExperiment)
# 将Seurat对象转为SCE
sce <- as.SingleCellExperiment(pbmc)
# 运行scDblFinder
set.seed(42)
sce <- scDblFinder(sce, clusters = TRUE)
# 查看结果
table(sce$scDblFinder.class)
# singlet doublet
# 8500 680
# 将结果转回Seurat
pbmc$scDblFinder_class <- sce$scDblFinder.class
pbmc$scDblFinder_score <- sce$scDblFinder.score
# 可视化
FeaturePlot(pbmc, features = "scDblFinder_score")
DimPlot(pbmc, group.by = "scDblFinder_class")
# 过滤
pbmc_clean <- subset(pbmc, scDblFinder_class == "singlet")
第五步:多样本的doublet检测策略¶
白话解释:如果有多个样本混在一起测序(hash tagging或pooling),可以利用SNP差异来鉴定doublet,这比计算方法更准确。
# 使用Demuxlet(基于SNP的方法)
# 需要参考VCF文件
demuxlet \
--sam possorted_bam.bam \
--vcf donors.vcf \
--field GP \
--out demuxlet_result
# 或使用Vireo(更灵活)
cellsnp-lite \
-s possorted_bam.bam \
-b barcodes.tsv \
-O cellsnp_output \
-R genome1K.phase3.SNP_AF5e2.chr1toX.hg38.vcf.gz \
-p 20 \
--minMAF 0.1 \
--minCOUNT 20
vireo -c cellsnp_output \
-N 4 \
-o vireo_output \
--randSeed 42
实战命令速查¶
# Scrublet一行运行
import scrublet as scr
scores, preds = scr.Scrublet(adata.X, expected_doublet_rate=0.06).scrub_doublets()
# Scanpy内置(基于Scrublet)
sc.pp.scrublet(adata, expected_doublet_rate=0.06)
# scDblFinder一行运行
sce <- scDblFinder(as.SingleCellExperiment(seurat_obj))
# 批量处理多个样本
library(scDblFinder)
sample_list <- SplitObject(merged_seurat, split.by = "sample")
for (s in names(sample_list)) {
sce <- as.SingleCellExperiment(sample_list[[s]])
sce <- scDblFinder(sce)
sample_list[[s]]$doublet <- sce$scDblFinder.class
}
面试常问点¶
Q1: 什么是同型doublet和异型doublet?为什么区分很重要? A: 同型doublet由两个相同类型的细胞组成(如两个T细胞),异型doublet由不同类型的细胞组成(如T细胞+B细胞)。异型doublet表达谱介于两个类型之间,比较容易用计算方法检测。同型doublet表达谱与正常细胞相似,几乎不可能通过计算检测,只能通过基于SNP的方法鉴定。
Q2: 如何确定期望的doublet率? A: 10x Genomics平台的doublet率约为每1000个回收细胞0.8%。如果回收了5000个细胞,期望doublet率约4%;10000个细胞约8%。具体数值可参考10x的技术文档。其他平台(如Drop-seq、inDrop)有不同的doublet率。
Q3: Scrublet和DoubletFinder的原理有什么共同点? A: 两者都基于"模拟doublet"策略:随机选取两个真实细胞的表达谱加和,创建人工doublet,然后在降维空间中找出与人工doublet邻近的真实细胞。区别在于具体的评分和阈值确定方法。
Q4: 多个样本应该合并后检测还是分别检测doublet? A: 应该分别检测。每个样本的doublet来自同一个实验,合并后不同样本的细胞不可能形成doublet。合并检测会错误地将不同样本的相似细胞标记为doublet。
Q5: doublet检测应该在分析流程的哪个阶段进行? A: 应该在标准化和初步聚类之后、正式的下游分析之前。需要先有PCA/UMAP等降维结果来定义邻域。移除doublet后应重新聚类。
易错点¶
- 多样本合并后检测:必须对每个样本单独运行doublet检测,不能合并后运行
- expected_doublet_rate设置不当:应根据实际加载细胞数计算,不能使用默认值
- DoubletFinder的pK优化:跳过pK优化步骤会导致结果不可靠
- 忽略同型doublet:计算方法只能检测异型doublet,应在论文中说明这个限制
- 过度移除:某些真实的过渡态细胞可能被误判为doublet,需结合生物学知识判断
补充知识¶
工具性能对比(Benchmark结果)¶
| 工具 | 语言 | 速度 | 准确性 | 推荐程度 |
|---|---|---|---|---|
| scDblFinder | R | 最快 | 最高 | 首选 |
| Scrublet | Python | 快 | 高 | Python首选 |
| DoubletFinder | R | 中等 | 高 | 经典方法 |
| scds | R | 快 | 中等 | 轻量级替代 |
| Solo | Python | 慢(深度学习) | 高 | 大数据集 |
不同平台的预期doublet率¶
| 平台 | doublet率 | 备注 |
|---|---|---|
| 10x Chromium | ~0.8%/1000 cells | 加载越多doublet率越高 |
| Drop-seq | ~1-5% | 取决于细胞浓度 |
| Smart-seq2 | ~0% | 单细胞分选,不存在 |
| CITE-seq | 同10x | 额外蛋白barcode可辅助 |