3. 批次效应检测方法(PCA、UMAP可视化)
讲完了批次效应的来源,咱们得聊聊怎么把它「揪出来」。你想想看,数据整合完了,你总得知道矫正做得到不到位,对吧?
我个人习惯,在跑任何复杂算法之前,先做一轮可视化摸底。说白了,就是给数据拍张「X光片」。这张片子,就是 PCA 和 UMAP。
3.1 为什么首选 PCA 和 UMAP
这两个方法,几乎成了单细胞数据分析的「标准动作」。但你要明白,它们在看批次效应这件事上,角色完全不同。
| 特性 | PCA(主成分分析) | UMAP(均匀流形逼近与投影) |
|---|---|---|
| 数学本质 | 线性降维,追求方差最大化 | 非线性降维,保留局部与全局结构 |
| 批次效应表现 | 在前几个主成分上「分层」或「分离」 | 形成明显的「簇团」或「岛状」分离 |
| 计算速度 | 极快,几秒出结果 | 较慢,尤其细胞数 > 10万时 |
| 主要用途 | 快速摸查、确定主成分数 | 精细展示、成果发表 |
| 对异常值敏感度 | 高 | 低 |
我刚开始做单细胞项目时,总迷信 UMAP 的视觉效果,觉得它漂亮。后来吃过一次亏:一个样本的 UMAP 分得很开,但 PCA 一看,其实只是那个样本的线粒体比例特别高。PCA 的线性特性,有时能帮你更快地找到问题根源。
核心观点: PCA 做「体检」,UMAP 做「展示」。两个缺一不可。
3.2 PCA 检测实操
咱们来看具体怎么操作。假设你已经有了一个整合后的 Seurat 对象或 AnnData 对象。
3.2.1 R 语言(Seurat)中的 PCA 可视化
# 假设你的 Seurat 对象叫 'combined'
# 先运行 PCA(如果还没做)
combined <- RunPCA(combined, features = VariableFeatures(combined))
# 按样本批次着色,看有没有分离
DimPlot(combined, reduction = "pca", group.by = "orig.ident") +
ggtitle("PCA - 按样本批次着色")
你会看到类似这样的图:理想状态是各样本的细胞均匀混在一起。如果某个样本的细胞在 PC1 或 PC2 上明显偏向一侧,那么批次效应很可能存在。
我的小技巧: 别只看前两个主成分。有时候 PC3 和 PC4 反而能暴露出更隐蔽的技术差异。我会循环检查前 10 个 PC,用 DimHeatmap() 看看哪些基因在驱动这些成分。
3.2.2 Python(Scanpy)中的 PCA 可视化
import scanpy as sc
# 假设你的 AnnData 对象叫 'adata'
sc.tl.pca(adata, n_comps=50)
sc.pl.pca(adata, color='batch', title='PCA 按批次着色')
同样的逻辑。如果出现明显的分层,这就是一个明确的信号。
3.2.3 量化批次效应:PCA 方差分解
光看还不够,我建议用量化指标来确认。一个常用的方法是看批次变量能解释多少方差。
# 在 R 中用 'adonis' 或 'PERMANOVA' 做方差分解
library(vegan)
# 提取前 30 个 PC 的坐标
pca_coords <- Embeddings(combined, reduction = "pca")[, 1:30]
# 看批次对 PC 坐标的贡献
adonis_result <- adonis(pca_coords ~ batch, data = combined@meta.data, method = "euclidean")
print(adonis_result$aov.tab)
如果 R² 值 > 0.1,那说明批次效应已经相当显著了,必须处理。
我曾经踩过的坑: 有次我的 PCA 看起来混得很好,R² 也很低,但 UMAP 却一塌糊涂。后来发现,是因为那个批次效应藏在非线性的高维结构中,PCA 的「线性眼镜」看不到。所以,PCA 说「没问题」不代表真的没问题,一定要结合 UMAP 做最终判断。
3.3 UMAP 检测实操
UMAP 的调参很敏感。很多人在这一步随便跑一下,结果被误导。我给你几个关键点。
3.3.1 标准流程
# Seurat
combined <- RunUMAP(combined, dims = 1:30)
DimPlot(combined, reduction = "umap", group.by = "orig.ident")
# Scanpy
sc.pp.neighbors(adata, n_neighbors=15, n_pcs=30)
sc.tl.umap(adata)
sc.pl.umap(adata, color='batch')
| 参数 | 默认值 | 批次效应检测时的建议 | 为什么? |
|---|---|---|---|
n_neighbors |
15 | 15-30 | 值越小,越强调局部结构;值越大,越看到全局趋势。检测批次效应建议用稍大的值,避免把噪声放大。 |
min_dist |
0.3 | 0.1-0.5 | 控制点的聚集程度。0.1 时簇更紧凑,0.5 时更分散。初次看批次效应,用 0.3 比较稳妥。 |
n_components |
2 | 2 或 3 | 2D 足够检测大部分批次效应。3D 交互式查看有时能发现隐藏的分层。 |
经验之谈: 我习惯先跑一次默认参数的 UMAP。如果看到批次分离,我会调整 n_neighbors 从 15 到 50,看看分离是「鲁棒的模式」还是「参数敏感的假象」。真正的批次效应,应该在不同的 n_neighbors 下都能看到。
3.4 如何「看」懂这些图
很多人只盯着图上有没有不同颜色的点混在一起。但有时候,批次效应很微妙。我给你列个检查清单。
- 完全重叠:理想状态,样本间混合均匀。恭喜,你可能没有批次效应。
- 渐变过渡:某一样本的细胞,沿着 UMAP 的某个方向「飘移」到另一个样本的位置。常见于测序深度差异。
- 硬边界分离:两个样本之间存在明显的「鸿沟」。这是最严重的批次效应,几乎必须矫正。
- 一个小簇单独分离:往往不是批次效应,而是某个细胞类型(如浆细胞)只在其中一个样本中出现。
教你一个实用技巧: 把 UMAP 图按基因表达量着色。如果分离的样本刚好高表达一组线粒体基因或核糖体基因,那很可能是细胞质量导致的批次效应,而不是生物学差异。
3.5 本章知识体系
下面这张图,总结了我们刚才说的检测逻辑。从原始整合数据开始,经过 PCA 和 UMAP 两条路径,最终得出批次效应是否存在的判断。
3.6 常见误区与避坑指南
- 误区一:只看 UMAP 不看 PCA。 个人建议还是先跑 PCA,省时间,能用线性视角帮你发现基础问题。
- 误区二:忽视颜色编码。 你想想看,如果批次标签的颜色本身对比度就很低,你根本看不出来有没有分离。我一般用
ggsci或者paletteer里高对比度的调色板。 - 误区三:对 UMAP 的随机性过于自信。 UMAP 每次运行结果可能略有差异。我会固定随机种子(
set.seed(42)或random_state=42),确保结果可重复。
我曾经踩过的一个深坑: 有次在处理一个包含 8 个样本的心肌细胞数据时,UMAP 上两个批次分庭抗礼。我花了整整两天调矫正参数,结果发现——其中一个样本其实是心室组织,另一个是心房组织。批次效应和生物学差异混在一起,UAMP 检测不出来这个区别。后来我用 FindAllMarkers() 看了差异基因,才发现真相。记住,检测批次效应的前提是你要确认它不是生物学差异。
好了,检测这一步讲完了。你现在应该能对你手上的数据做个全面的「体检」了。从 PCA 的快速扫描,到 UMAP 的精细查看,再到 adonis 的量化确认——这三板斧砍下来,你的批次效应有没有问题,心里就有数了。