批次效应的可视化探索:用PCA、热图、UMAP做初步诊断

拿到表达矩阵后的第一件事是什么?

我个人习惯——不急着跑校正,先做可视化。

为什么?

因为数据有没有问题,眼睛一看就知道。批次效应再隐蔽,在降维图上也藏不住。你想想看,如果PCA或者UMAP图上一眼就看出来样本按批次分成几坨,那说明批次效应已经大到不能忽视了。

这一章,咱们就聊聊怎么用PCA、热图、UMAP这三种工具,给你的RNA-seq数据做一次"体检"。

批次效应可视化诊断流程 原始表达矩阵 PCA降维 热图聚类 UMAP降维 综合诊断 是否校正 💡 诊断要点 • 三种方法交叉验证 • 两两方法一致更可靠 • 单一方法异常须警惕

1. PCA:最快的全局扫描仪

PCA(主成分分析)是我最常用的第一眼工具。它把高维表达数据压缩到前几个主成分里,然后按批次上色,一看便知。

说白了,PCA就是问一个问题:样本间最大的变异来源是什么?如果答案是"批次",那你得小心了。

核心判断标准:

  • PC1 或 PC2 明显按批次分组 → 批次效应强烈
  • 同一生物学条件的样本跨批次混在一起 → 批次效应可控
  • PC1 是生物学分组,PC2 是批次 → 批次效应存在但可能可校正

来段代码看看吧。以下是用 R 做的 PCA 可视化:

# 表达矩阵:基因×样本,已做标准化
expr_mat <- log2(expr_mat + 1)

# PCA计算
pca_res <- prcomp(t(expr_mat), scale. = TRUE, center = TRUE)
pca_df <- data.frame(
  PC1 = pca_res$x[, 1],
  PC2 = pca_res$x[, 2],
  batch = batch_info,
  condition = condition_info
)

# 计算解释方差比例
var_exp <- round(100 * summary(pca_res)$importance[2, 1:2], 1)

# 绘图
library(ggplot2)
ggplot(pca_df, aes(PC1, PC2, color = batch, shape = condition)) +
  geom_point(size = 3.5, alpha = 0.8) +
  xlab(paste0("PC1 (", var_exp[1], "%)")) +
  ylab(paste0("PC2 (", var_exp[2], "%)")) +
  theme_bw(base_size = 14) +
  ggtitle("PCA 按批次着色")

我记得有一次做TCGA数据整合,PC1直接分成了两个批次,PC2才是真实的肿瘤vs正常差异。那会儿我就意识到——批次效应不查不行。

一个小技巧:

如果样本量较大,可以用 geom_point(size = 2, alpha = 0.6) 避免点重叠。我还会额外画一个 95% 置信椭圆,帮眼睛聚焦——按批次画椭圆,看它们叠不重叠。

另外,别只看PC1和PC2。有时候批次效应会藏在PC3或PC4里。我建议至少看到PC4:

# 快速扫前4个主成分
pca_df_pc34 <- data.frame(
  PC3 = pca_res$x[, 3],
  PC4 = pca_res$x[, 4],
  batch = batch_info
)

ggplot(pca_df_pc34, aes(PC3, PC4, color = batch)) +
  geom_point(size = 3) +
  theme_bw()

2. 热图:样本间相似性的"红外照片"

PCA看的是全局变异方向,而热图看的是样本间的成对相似性。说白了,它回答的是:哪些样本"长得像"?

我一般用样本间表达相关性来做热图,再配上批次注释条,非常直观。

library(pheatmap)
library(RColorBrewer)

# 计算样本间Pearson相关
cor_mat <- cor(expr_mat, method = "pearson")

# 准备注释信息
anno_df <- data.frame(
  Batch = batch_info,
  Condition = condition_info,
  row.names = colnames(expr_mat)
)

# 自定义颜色
anno_colors <- list(
  Batch = c("Batch1" = "#E41A1C", "Batch2" = "#377EB8", "Batch3" = "#4DAF4A"),
  Condition = c("Control" = "#FF7F00", "Treatment" = "#984EA3")
)

# 画热图
pheatmap(cor_mat,
         annotation_col = anno_df,
         annotation_colors = anno_colors,
         clustering_method = "ward.D2",
         show_rownames = FALSE,
         show_colnames = TRUE,
         main = "样本间相关性热图",
         color = colorRampPalette(rev(brewer.pal(9, "RdBu")))(100),
         fontsize_row = 8)

看热图的时候,我关注两个点:

  • 树状图的分簇结构——如果样本先按批次分成几大簇,再按生物学条件分,那批次效应很明显。
  • 颜色块的模式——批次内部的颜色是否明显比批次间更"红"(相关性更高)。

避坑指南:

我曾经因为样本注释搞混了,热图画出来全是乱的。后来排查了半天,才发现是批次标签贴错了。所以——画热图之前,一定先确认注释列的准确性。一个错标,能带偏整个分析。

3. UMAP:局部结构的放大镜

PCA擅长抓全局,但它有个弱点——批次效应如果只影响局部基因模块,PCA可能看不出来。这时候就该UMAP上场了。

UMAP的核心思路是保留样本间的"近邻关系",它对局部结构更敏感。说白了,PCA看"大方向",UMAP看"小细节"。

library(umap)

# UMAP降维
umap_config <- umap.defaults
umap_config$n_neighbors <- 15    # 控制局部vs全局的平衡
umap_config$min_dist <- 0.1      # 控制点的聚集程度

umap_res <- umap(t(expr_mat), config = umap_config)
umap_df <- data.frame(
  UMAP1 = umap_res$layout[, 1],
  UMAP2 = umap_res$layout[, 2],
  batch = batch_info,
  condition = condition_info
)

# 绘图
ggplot(umap_df, aes(UMAP1, UMAP2, color = batch, shape = condition)) +
  geom_point(size = 3, alpha = 0.8) +
  theme_bw(base_size = 14) +
  ggtitle("UMAP 按批次着色")

UMAP 参数调优经验:

  • n_neighbors 默认15,样本多可以调大到30-50,更关注全局
  • min_dist 默认0.1,调小到0.01会让点更聚集,便于发现离群
  • 我个人习惯:先用PCA扫一遍,再用UMAP做double-check

我曾经有一个项目,PCA做出来看起来还行——PC1是生物学分组,PC2有点乱但不太明显。结果UMAP一跑,同一条件下的样本被批次分成了两堆。那叫一个原形毕露。

为什么PCA没看出来?

因为批次效应影响的基因数量少,在PCA的全局方差里占比小,被前几个主成分"淹没了"。而UMAP保留了局部近邻结构,批次导致的局部差异反而被放大了。

4. 三种方法怎么选?

来,我帮你总结一下。下面这个表格,我每次做项目都会对照着看一遍:

方法 核心目的 最适合的场景 关键警示信号
PCA 检测全局最大变异方向 初步快速筛查,尤其样本量大时 PC1/PC2 按批次分离,解释方差 > 20%
热图 检查样本间整体相似性 中等样本量,需要直观展示聚类结构 树状图先按批次分簇,而非按条件
UMAP 保留局部结构的精细降维 PCA结果不明确,或批次效应可能较微弱 同条件样本被批次重新分堆

一个常见的误区:

很多人只看一种图就下结论。我在项目中踩过这个坑——PCA没发现问题,就以为数据是干净的。后来加了UMAP才发现完全不是那么回事。三种方法交叉验证,才能做判断。

5. 综合诊断:你的数据到底有没有批次效应?

做完三种可视化,该怎么汇总判断?我个人习惯按下面几步走:

  1. 先看PCA——前4个主成分有没有按批次分离?有的话,批次效应大概率存在。
  2. 再看热图——树状图的第一层分支是按批次还是按条件?如果是批次,说明批次效应很强。
  3. 最后看UMAP——有没有PCA没发现的局部批次结构?特别关注同一条件下的样本是否跨批次混在一起。
  4. 交叉对比——至少两种方法指向同一结论,才算确认。

如果三种方法都指向"存在明显批次效应",那就别犹豫了,接着看下一章怎么校正。如果只有一种方法有信号,其他两种正常,那批次效应可能比较弱,可以再深入检查一下。

记住一句话:

可视化不是目的,是手段。它帮你决定"要不要校正"以及"校正方向对不对"。不要跳过这一步,也不要只依赖一种方法。