第二讲:批次效应的可视化探索

说起批次效应,我个人的习惯是:先别急着建模,先拿眼睛看看数据长什么样。

你想想,数据里有没有明显的批次分组?不同批次的样本是不是天然分开了?这些用肉眼看比跑统计模型要直观得多。这章我们就来聊聊五种可视化方法——箱线图、PCA、热图、密度图、MDS。每一种都是我的老伙计,在不同项目里帮我揪出过不少批次问题。

2.1 为什么先看可视化?

说白了,可视化是所有分析的“体检报告”。

我遇到过不少项目,分析师吭哧吭哧跑了一大堆统计检验,结果后来发现数据本身就有系统性的批次偏移。那感觉就像你花了一个月研究汽车的发动机,结果发现轮胎是方的。

可视化可以让批次效应在早期就暴露出来。你在这一步花10分钟,可能会节省后面好几天的排查时间。

2.2 箱线图:最直接的表达

箱线图是入门级的批次效应查看工具。它能告诉你:不同批次的样本,表达量分布是不是一致的。

假设我们有一个表达矩阵 expr,加上一个批次标签向量 batch。R的基础绘图就能完成:

# 随机选一个基因,比如第100个
gene_idx <- 100
boxplot(expr[gene_idx, ] ~ batch,
        main = "Gene 100 表达量分布 - 按批次",
        xlab = "批次", ylab = "表达量",
        col = c("#3498db", "#e74c3c", "#2ecc71"))

如果不同批次的中位数明显不一样,或者四分位距差别很大——嗯,那就要留个心眼了。

怎么看?

  • 中位数差异大:批次效应很可能是真实存在的。
  • 离散度不一致:有的批次波动大,有的批次波动小,这也是问题。
  • 异常点集中在某批次:这个批次可能有技术问题。
箱线图只能看单个基因。如果成千上万个基因都表现出类似的批次差异,这才有说服力。我曾经只盯着一个看,结果发现那是个随机波动...

2.3 PCA:降维看全局

PCA是我最常用的方法。它能把高维数据压缩到两三个维度,然后看看批次是不是“聚成一团”。

用R的 prcomp 函数做PCA很简单:

# 转置:行为样本,列为基因
pca_result <- prcomp(t(expr), scale. = TRUE)

# 提取前两个主成分
pca_data <- as.data.frame(pca_result$x[, 1:2])
pca_data$batch <- batch

# 绘图
library(ggplot2)
ggplot(pca_data, aes(x = PC1, y = PC2, color = batch)) +
  geom_point(size = 3, alpha = 0.8) +
  theme_minimal() +
  labs(title = "PCA:样本按批次着色")

关键判断标准:

  • 如果相同批次的样本在PCA图上紧挨在一起,不同批次明显分开——批次效应就相当明显了。
  • 如果同批次样本也散得很开,不同批次混在一起——那批次效应可能不严重。
  • PC1和PC2解释方差的比例要留意。如果头两个主成分只解释了不到20%,那这张图的可信度就要打点折扣。

我在一个单细胞RNA-seq项目里遇到过,PCA图上批次完全分成了两群。当时第一个反应就是:“完了,得好好校正了。”

2.4 密度图:分布形状的对比

密度图可以看成是箱线图的连续版本。它能更精细地显示表达量的分布形状。

# 随机选一个样本,在每个批次里各抽取一个
sample_ids <- tapply(1:ncol(expr), batch, function(x) x[1])

# 提取这三个样本的表达量
library(ggplot2)
df <- data.frame(
  expression = expr[1, sample_ids],
  batch = factor(batch[sample_ids])
)

ggplot(df, aes(x = expression, fill = batch)) +
  geom_density(alpha = 0.5) +
  theme_minimal() +
  labs(title = "密度图:同一基因在不同批次中的分布")

密度图能告诉你什么?

  • 峰的位置偏移:不同批次的分布中心不同。
  • 峰的形状不同:有的批次是双峰,有的是单峰,这通常说明批次间存在技术差异。
  • 尾部差异:有的批次高表达基因多,这也是批次效应的信号。

2.5 热图:批次效应的“全貌”

热图结合了聚类和颜色映射,能看到整体模式。我用它来观察批次是否在聚类树中形成独立分支。

# 计算样本间的相关性矩阵
cor_matrix <- cor(expr, method = "spearman")

# 用pheatmap绘制
library(pheatmap)
annotation <- data.frame(batch = factor(batch))
rownames(annotation) <- colnames(expr)

pheatmap(cor_matrix,
         annotation_col = annotation,
         annotation_row = annotation,
         main = "样本相关性热图 - 按批次标注",
         color = colorRampPalette(c("#3498db", "white", "#e74c3c"))(50))

怎么解读?

  • 同一批次的样本在热图里形成明显的色块——批次效应存在。
  • 聚类树甩出明显的批次分组——很可能是批次效应主导了聚类。
  • 如果批次标签和聚类结果基本无关——那你可以松一口气。

2.6 MDS:PCA的坚强替补

MDS(多维尺度分析)和PCA的思路类似,都是降维。区别在于MDS直接基于样本间的距离矩阵,不要求线性假设。

# 计算欧氏距离矩阵
dist_matrix <- dist(t(expr))

# 执行经典MDS
mds_result <- cmdscale(dist_matrix, k = 2)
mds_data <- as.data.frame(mds_result)
mds_data$batch <- batch

ggplot(mds_data, aes(x = V1, y = V2, color = batch)) +
  geom_point(size = 3, alpha = 0.8) +
  theme_minimal() +
  labs(title = "MDS:基于距离矩阵的批次效应可视化")

什么时候用MDS?

  • 数据不符合线性假设时,MDS往往比PCA更靠谱。
  • 想要使用非欧氏距离(比如曼哈顿距离、相关系数距离)时,MDS更灵活。
  • PCA和MDS的结论相互印证,会让你的分析更有说服力。

2.7 五种方法的对比表

方法 侧重点 优点 局限
箱线图 单个基因的分布差异 简单快速,一目了然 只能看单个基因,多基因需逐个检查
PCA 全局样本的聚类模式 降维效果好,方差解释度高 对异常值敏感,需要适当标准化
密度图 分布形状的精细对比 能发现双峰等复杂分布 一次只能看一个基因/一个样本
热图 整体相关性和聚类结构 直观展示批次相关模式 样本量大时视觉过载
MDS 基于任意距离的降维 灵活性高,不限于线性假设 对距离度量敏感,需要选择合适距离

2.8 核心流程:一张图说清楚

下面这张SVG图汇总了这五种可视化方法的使用流程。说白了,就是从原始数据出发,选择合适的可视化方式,最终判断批次效应是否存在。

批次效应可视化探索流程 原始表达矩阵 选择可视化维度:单个基因 / 全局模式 单基因 / 单样本分析 箱线图 密度图 热图 全局样本模式 PCA MDS 热图 批次效应是否存在? 需要批次校正 批次效应不明显

2.9 避坑指南

我曾经犯过的几个毛病:

  • 只看一种图就下结论:PCA说没问题,但热图可能反映出细微的模式。多角度交叉验证是王道。
  • 忽略了标准化:不做标准化直接跑PCA,结果全是表达量高的基因在主导。那场面,就像你在菜市场里用扩音器喊话——根本听不到正常声音。
  • 样本量太少:每个批次只有两三个样本时,任何可视化都很难给出可靠判断。这时宁可多收集数据,也不要强行分析。
  • 忘记检查离群样本:一个离群样本足以把PCA图扭曲得面目全非。先过滤再可视化,这是个好习惯。
我的经验法则:先做箱线图快速扫描2-3个关键基因,然后跑PCA看大局,最后用热图确认聚类结构。三管齐下,基本不会漏掉明显的批次效应。