3. 批次效应可视化:t-SNE与UMAP检测技巧
先问一个问题:你合并多个数据集后,画个PCA图发现不同批次的数据各自抱团,是不是第一反应就是“完蛋,有批次效应”?
其实未必。有些批次差异是生物学本身带来的,不能一棍子打死。这章我就带你用t-SNE和UMAP这两个降维可视化利器,把批次效应“看”出来。我用过的项目里,至少一半的批次效应问题是在图上直接发现的——比任何统计检验都直观。
3.1 为什么降维可视化对批次效应这么有效?
高维数据你没法直接画点,PCA虽然快但本质是线性投影,很多非线性偏移它抓不住。t-SNE和UMAP都是非线性方法,能把局部相似结构在二维平面里拉开,让你一眼看清样本到底是按生物学分组聚类,还是按批次分组聚类。
核心判断原则:好的批次校正后,不同批次的同类型细胞/样本应该混在一起,而不是各自成一团。
3.2 t-SNE与UMAP的快速对比
| 特性 | t-SNE | UMAP |
|---|---|---|
| 基本原理 | 概率分布匹配 + KL散度 | 拓扑流形 + 交叉熵 |
| 速度 | 慢(O(n²)) | 快(接近O(n log n)) |
| 全局结构保留 | 弱(只顾局部) | 较好(兼顾局部+全局) |
| 适用场景 | 小数据集、精细局部结构 | 大数据集、需要速度 |
| 随机性 | 每次运行结果略有不同 | 更稳定,可设置随机种子 |
我个人习惯:先用UMAP做快速排查,如果发现可疑的批次分离,再用t-SNE放大细节确认。别在一开始就用t-SNE调参,那太费时间了。
3.3 用Python跑起来:scanpy示例
假设你已经有了一个AnnData对象 adata,里面包含来自两个批次(batch1, batch2)的细胞,并且已经做了基本归一化。
import scanpy as sc
# 先做PCA降维到50个主成分(降低噪声)
sc.tl.pca(adata, n_comps=50, svd_solver='arpack')
# UMAP计算
sc.pp.neighbors(adata, n_neighbors=15, n_pcs=50)
sc.tl.umap(adata)
# t-SNE计算(scanpy内部调用openTSNE,速度还行)
sc.tl.tsne(adata, n_pcs=50, perplexity=30)
# 用批次信息着色
sc.pl.umap(adata, color='batch', title='UMAP colored by batch')
sc.pl.tsne(adata, color='batch', title='t-SNE colored by batch')
我曾经踩过一个坑:直接对原始count数据跑t-SNE,结果所有细胞挤成一坨,根本看不出结构。PCA降维这步不能省,去掉高维噪声才能让t-SNE、UMAP发挥效果。
3.4 如何解读图上的批次效应?
图上会看到两种典型情况:
- 完全分离:两个批次各自形成独立簇,中间没有过度细胞——这基本就是严重的批次效应,必须校正。
- 部分重叠但颜色不均匀:两个批次在空间上有交叉,但某个区域里几乎全是批次A,另一块全是批次B——这种也需要关注,可能批次效应叠加了生物学差异。
- 均匀混合:每个局部区域里两个批次的点大致均匀分布——恭喜,说明批次效应不显著,或者你的数据本身采集得很好。
3.5 定量辅助:用kNN比例评分
光看图不够客观?我经常用一个简单指标:计算每个细胞周围最近邻中来自同批次的占比,然后取所有细胞的平均值。如果这个值明显大于总体批次比例,说明存在局部聚集。
from sklearn.neighbors import NearestNeighbors
import numpy as np
# 用UMAP坐标计算
umap_coords = adata.obsm['X_umap']
batch_labels = adata.obs['batch'].values
nbrs = NearestNeighbors(n_neighbors=20, algorithm='ball_tree').fit(umap_coords)
distances, indices = nbrs.kneighbors(umap_coords)
neighbor_batch = batch_labels[indices]
same_batch_ratio = np.mean(neighbor_batch == batch_labels[:, None], axis=1)
print(f"Mean same-batch ratio: {np.mean(same_batch_ratio):.3f}")
小提示:如果这个比值超过0.6(假设总体批次比例各占50%),我就倾向于认为有批次效应需要处理。
3.6 批次效应检测流程总图
下面这张SVG把整个过程串起来,省得你回头翻代码:
3.7 注意事项与避坑
避坑1:别只用一种可视化方法。我遇到过UMAP显示混合完美,t-SNE却暴露出两个小亚群完全被批次分开的情况。两种方法互补,交叉验证更可靠。
避坑2:perplexity(t-SNE)和n_neighbors(UMAP)这两个参数对结果影响很大。默认值(t-SNE 30,UMAP 15)不一定适合你的数据。如果细胞数超过10万,把perplexity放大到50-100试试,否则小簇会被忽略。
实用技巧:画图时把批次和生物学分类(如细胞类型)分别着色放在同一张图旁边对比。如果批次分离恰好与某个稀有细胞类型重合,那可能不是批次效应,而是该类型只在某一个批次中出现。这种情况需要用harmony或ComBat做轻度校正,保留生物学差异。
嗯,到这步你已经能通过可视化判断批次效应的强弱了。下一线项目里,我会在跑任何校正算法之前,先花5分钟做一遍t-SNE+UMAP双图诊断。很多时候,一张图就告诉你该不该继续往下走了。