2. 批次效应的可视化检测:PCA、UMAP、热图与箱线图

数据拿到手,别急着做校正。我个人的习惯是——先可视化,看看批次效应到底存不存在、有多严重。这一步省不了,而且往往决定了后续校正策略的选择。

说白了,可视化检测就是给你的数据"拍X光片"。PCA、UMAP、热图、箱线图这四种方法,各有各的视角。结合起来看,基本能把批次效应的底细摸清楚。

核心思路: 通过降维或分布展示,将"批次标签"映射到可视空间,观察批次是否形成明显分离或分布偏移。如果看不到明显分离,可能不需要校正;如果分离明显,就得针对性处理。

2.1 PCA — 看全局分离度

PCA是第一个上场的。它把高维数据压到2-3个主成分上,保留最大的方差信息。你只需要把前两个主成分画成散点图,用颜色区分批次,就能看出个大概。

我在项目中遇到过一批代谢组学数据,六个批次,PCA一跑,前两个主成分直接分出三个簇。当时我就知道——这事不简单,校正跑不掉了。

代码示例:PCA检测批次效应

import pandas as pd
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns

# 模拟数据:100个样本,50个特征,3个批次
np.random.seed(42)
n_samples, n_features, n_batches = 100, 50, 3
data = []
batch_labels = []
for b in range(n_batches):
    # 每个批次加入偏移
    offset = np.random.normal(0, 2, n_features)
    batch_data = np.random.normal(0, 1, (n_samples // n_batches, n_features)) + offset
    data.append(batch_data)
    batch_labels.extend([f'Batch_{b+1}'] * (n_samples // n_batches))
data = np.vstack(data)
batch_labels = np.array(batch_labels)

# PCA
pca = PCA(n_components=2)
pca_result = pca.fit_transform(data)

# 绘图
plt.figure(figsize=(8, 6))
sns.scatterplot(x=pca_result[:, 0], y=pca_result[:, 1],
                hue=batch_labels, palette='Set2', s=60)
plt.title('PCA: 批次效应可视化')
plt.xlabel('PC1 ({:.1f}%)'.format(pca.explained_variance_ratio_[0] * 100))
plt.ylabel('PC2 ({:.1f}%)'.format(pca.explained_variance_ratio_[1] * 100))
plt.legend()
plt.show()

怎么看结果?如果不同批次的点混在一起、边界模糊,说明批次效应不明显。如果各批次形成独立团簇、边界清晰,那你得警惕了。

我的经验: PCA对全局结构敏感,但对局部偏移不太灵。有时候PCA看起来混得不错,换UMAP却能看出蹊跷。所以别只看一种方法。

2.2 UMAP — 捕捉局部结构

UMAP和PCA的视角不同。它更擅长保留数据的局部邻域结构。什么意思呢?就是同一批次的样本应该靠得近,不同批次如果被强行分开,UMAP会把它放大。

我记得有一次做单细胞转录组数据,PCA看起来三个批次重叠得挺好,但UMAP一跑,其中一批次明显漂出去一个"小尾巴"。这就是局部结构暴露出来的问题。

代码示例:UMAP检测批次效应

import umap

# UMAP降维
reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42)
umap_result = reducer.fit_transform(data)

# 绘图
plt.figure(figsize=(8, 6))
sns.scatterplot(x=umap_result[:, 0], y=umap_result[:, 1],
                hue=batch_labels, palette='Set2', s=60)
plt.title('UMAP: 批次效应可视化(局部结构保持)')
plt.xlabel('UMAP_1')
plt.ylabel('UMAP_2')
plt.legend()
plt.show()

UMAP有两个重要参数:n_neighbors 控制局部 vs 全局的平衡,min_dist 控制点的聚集程度。你想想看,如果批次效应很细微,把 n_neighbors 调小一点,更容易把局部差异暴露出来。

注意: UMAP的随机性比PCA大,每次运行结果可能略有不同。建议固定 random_state,或者运行多次看稳定模式。

2.3 热图 — 看表达模式变化

热图展示的是所有样本在所有特征上的表达强度,配合行/列聚类,能直观看到批次是否形成独立的表达模式块。

说白了,如果热图的列聚类把样本按批次分开,形成明显的"色块条带",那就是批次效应的铁证。

代码示例:热图检测批次效应

from scipy.cluster.hierarchy import linkage
import seaborn as sns

# 取前30个特征做展示
data_sub = data[:, :30]
# 行:特征,列:样本
sns.clustermap(data_sub.T, method='ward', metric='euclidean',
               col_colors=batch_labels, cmap='RdBu_r',
               figsize=(10, 8), xticklabels=False)
plt.show()

我在项目中遇到过一种情况:热图的列聚类先按批次分了三大块,但每块内部又有细分。这说明批次效应存在层级结构——可能是不同实验批次下的子批次差异。这种情况只用PCA很容易忽略。

技巧: 热图一定要做聚类排序。不做聚类的热图就像没排序的Excel表,看不出模式。另外,颜色映射用 RdBu_r 或 vlag 这类发散型色板,更容易突出差异。

2.4 箱线图 — 看分布偏移

箱线图看的是单个特征的分布在批次间的变化。虽然它只盯一个特征,但能告诉你偏移的方向和幅度。

比如某个特征在批次1的中位数是5,在批次2变成了8,箱体位置明显错开——这就是分布偏移。多个特征都出现这种情况,批次效应就跑不掉了。

代码示例:箱线图检测批次效应

# 选3个特征展示
features_show = [0, 5, 12]
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for i, feat_idx in enumerate(features_show):
    df_plot = pd.DataFrame({
        'value': data[:, feat_idx],
        'batch': batch_labels
    })
    sns.boxplot(x='batch', y='value', data=df_plot, ax=axes[i],
                palette='Set2')
    axes[i].set_title(f'Feature {feat_idx}')
    axes[i].set_xlabel('')
plt.tight_layout()
plt.show()

嗯,这里要注意:箱线图对样本量敏感。如果某个批次只有几个样本,箱线图的四分位范围可能不稳定,这时候换成个体数据点的 strip plot 或者 violin plot 会更靠谱。

避坑: 我曾经吃过一次亏——只看箱线图的中位数觉得没问题,但方差差异很大。批次效应不只是均值偏移,方差不齐也是问题。所以箱线图要同时关注箱体位置和箱体宽度。

2.5 四种方法对比与选择

到底用哪种?我建议不要单选,而是组合使用。下面这张表是我在实际项目中的经验总结:

方法 视角 优点 不足 最适用场景
PCA 全局方差 稳定、可重复、解释性强 对局部偏移不敏感 初步筛查、整体评估
UMAP 局部邻域 能发现细微分离、可视化效果好 随机性较大、参数敏感 深度检测、探索性分析
热图 表达模式 能同时看所有特征、可发现层级结构 特征多时视觉拥挤、需聚类 多特征模式识别、层级批次效应
箱线图 单特征分布 定量、能看偏移方向和幅度 一次只能看少量特征 关键特征验证、分布偏移诊断

你想想看,这四种方法就像四个不同角度的探照灯。PCA照全局,UMAP照局部,热图照整体模式,箱线图照单特征细节。组合起来,才能把批次效应看得透彻。

批次效应可视化检测方法框架 多批次原始数据 PCA 全局方差最大化 UMAP 局部邻域结构保持 热图 表达模式 + 聚类 箱线图 单特征分布偏移 综合判断:是否存在批次效应? 批次效应明显 → 需要校正 PCA/UMAP分离、热图成块、箱线图偏移 批次效应微弱 → 无需校正 各批次混叠、分布基本一致 💡 策略建议: 先跑PCA快速筛查 → 再用UMAP深度检测 → 热图确认模式 → 箱线图定位具体特征。四种方法交叉验证,结论更可靠。

2.6 实战中我常用的分析流程

光讲理论不够,我把实际项目中的操作步骤列出来,你可以直接照着来:

  1. 第一步:PCA快速筛查 — 跑个PCA散点图,看批次是否明显分离。这一步30秒出图,心里先有个数。
  2. 第二步:UMAP深度检测 — 如果PCA看起来还行,用UMAP再查一遍。调小 n_neighbors 到10左右,看局部是否有隐藏偏移。
  3. 第三步:热图确认模式 — 取表达量变化最大的前50个特征,画聚类热图。看列聚类是否按批次分组。
  4. 第四步:箱线图定位特征 — 找到热图中差异最明显的几个特征,画箱线图确认分布偏移的方向和幅度。
  5. 第五步:综合判断 — 如果四种方法超过两种指向"有明显批次效应",那就准备校正吧。
重要提醒: 可视化检测只是"看",不是"证明"。有时候肉眼觉得分开了,但统计检验(如ANOVA、PERMANOVA)可能告诉你并不显著。我建议可视化搭配统计检验一起用,定性和定量结合,结论才站得住脚。

2.7 小结

这一章我们聊了四种可视化检测方法。PCA看全局,UMAP看局部,热图看模式,箱线图看分布。没有哪一种方法是万能的,组合使用才能把批次效应的底细摸清楚。

我个人的工作流是:PCA + UMAP 做快速筛查,热图 + 箱线图做深度确认。四张图出来,批次效应有没有、在哪些特征上、严重到什么程度,心里基本有数了。

可视化检测做扎实了,下一步的校正才能有的放矢。不然你连问题都没看清就急着上手校正,很容易搞出"校正后比校正前更糟"的局面。