跳到正文
百沐一下百沐一下
本节目录

批次整合:Harmony / CCA / RPCA 对比

跟完这篇,您能把来自多个样本、多次建库的单细胞数据合到一张图谱上,让同一种细胞跨样本对齐、而不是按样本各聚一堆;您会在 Harmony、CCA、RPCA 三种主流方法之间按数据规模和批次强弱选对一种,看得出整合是「不足」还是「过度」,并且知道整合之后差异分析该回到哪份数据上做。

为什么单细胞要「整合」,而不只是「去批次」

把几个样本、几次实验的单细胞数据放在一起分析,几乎必然遇到批次效应:同一种细胞,只因来自不同样本、不同建库批次,在降维图上就被拆成各自一坨。批次整合(integration) 要解决的就是这件事——让「同一种细胞」跨批次落到一起,好统一聚类、统一注释。

它和散装(bulk)RNA-seq 的「去批次」是两回事,别混为一谈:

bulk 去批次单细胞整合
目标差异分析时不被批次带偏同类细胞跨样本对齐,能一起聚类
校正对象表达矩阵,或把批次写进模型当协变量主要是低维嵌入(PCA 坐标),不改表达值
常态能用协变量就不动数据合并多样本时几乎总要做

有一条底线要先立住:只按「技术批次」整合,不要按您想比较的「生物学分组」整合。 如果把 disease / control 当成批次去对齐,等于亲手把您要研究的差异抹平了。散装数据里批次和分组的取舍,见 批次效应识别与去除

开始之前:您手上要有什么

整合发生在「建对象、质控、标准化」之后、「聚类」之前。动手前请确认:

  1. 一个合并好的 Seurat 对象meta.data 里有一列(下面叫 batch)标明每个细胞来自哪个样本 / 批次。上游怎么走,见 单细胞分析全流程单细胞质控怎么做
  2. 每个样本都已各自标准化、找过高变基因。整合正是在这些高变基因上做对齐。

下面示例以 Seurat v5 为准。v5 把「多样本整合」统一成 IntegrateLayers 一个入口,换方法只需换一个参数——这恰好方便我们把三种方法摆在一起比。

library(Seurat)

# obj:已 merge 的多样本对象,meta.data 有 batch 一列
# Seurat v5:先把 RNA 表达按 batch 拆成多个 layer,整合就在 layer 之间做
obj[["RNA"]] <- split(obj[["RNA"]], f = obj$batch)

obj <- NormalizeData(obj)
obj <- FindVariableFeatures(obj)
obj <- ScaleData(obj)
obj <- RunPCA(obj)

先看一眼「不整合会怎样」

在动手整合前,先用未校正的 PCA 跑一遍降维,按批次上色看看。这一步是为了确认「到底需不需要整合、以及整合后好了多少」有个对照。

obj <- FindNeighbors(obj, dims = 1:30, reduction = "pca")
obj <- RunUMAP(obj, dims = 1:30, reduction = "pca")

# 按批次上色:若同类细胞明显按 batch 分开,就说明需要整合
DimPlot(obj, reduction = "umap", group.by = "batch")
  • 若各批次已经充分混匀、只按细胞类型分开,那批次效应很小,未必需要整合,别为做而做。
  • 若同一群细胞被批次拆成平行的几坨,就进入下一步。
  • dims = 1:30 是常用取值,按肘图(ElbowPlot)微调,非固定值。

三种方法怎么跑

v5 里三种方法都是 IntegrateLayers 的一个 method 参数,输出一个新的降维(new.reduction),供后续聚类和 UMAP 使用。实际分析选一种即可;这里三种都写出来,是为了让您对照跑、对照看。

# 方法一:CCA —— 典型相关分析找跨批次的共享变异
obj <- IntegrateLayers(obj, method = CCAIntegration,
                       orig.reduction = "pca", new.reduction = "integrated.cca")

# 方法二:RPCA —— 相互投影 PCA,更保守、更快
obj <- IntegrateLayers(obj, method = RPCAIntegration,
                       orig.reduction = "pca", new.reduction = "integrated.rpca")

# 方法三:Harmony —— 在 PCA 空间迭代软聚类并逐簇校正(需先装 harmony 包)
obj <- IntegrateLayers(obj, method = HarmonyIntegration,
                       orig.reduction = "pca", new.reduction = "harmony")

拿到整合后的降维,后续步骤就把 reduction 指向它,其余和常规流程一样:

# 以选定的 RPCA 结果为例
obj <- FindNeighbors(obj, reduction = "integrated.rpca", dims = 1:30)
obj <- FindClusters(obj, resolution = 0.5)
obj <- RunUMAP(obj, reduction = "integrated.rpca", dims = 1:30)

# 左图看批次是否混匀,右图看聚类
DimPlot(obj, reduction = "umap", group.by = c("batch", "seurat_clusters"))

Harmony 也可以脱离 IntegrateLayers、用它自己的接口跑:harmony::RunHarmony(obj, group.by.vars = "batch"),同样产出一个 harmony 降维。两种入口结果一致,用顺手的即可。

三种方法的适用与代价

三种方法都在「让批次混匀」和「别把真细胞类型也混掉」之间权衡,只是取舍点不同。

方法大致原理更适合代价 / 风险
Harmony在 PCA 空间迭代做软聚类,逐簇估计并扣除批次偏移样本多、细胞多、要快;批次结构相对温和批次差异极强时可能校正不足;是嵌入层校正,不给校正后的表达矩阵
CCA找跨批次的共享变异方向,据此确定「锚点」细胞对再对齐批次差异较大但共享细胞类型多;样本数不太大计算和内存开销大,细胞一多就慢;相对更容易过度整合,把弱差异抹平
RPCA锚点框架同 CCA,但把每个批次相互投影到对方 PCA 空间找锚点,更保守大数据集;批次差异大又怕过整合;已知各批共享类型明确更保守,故批次差异极大或共享类型很少时可能整合不足;有时需调 k.anchor

几条实用的经验:

  • 先试 RPCA 或 Harmony:两者都快、都稳,适合作默认起点。数据大、样本多时尤其如此。
  • CCA 更「敢对齐」:当不同批次共享的细胞类型很多、您担心整合不足时它有优势,但对应地更要警惕过度整合。
  • 已有系统的基准评测比较过这类方法,共识是没有哪一种在所有场景都最好——方法选择要看批次强弱、共享类型多少和数据规模,别照搬别人论文里的选择。
  • 换方法很便宜(改一个 method 参数),同一份数据跑两三种、对照下一节的诊断图再定,比空想哪种「更好」靠谱。

整合过度还是不足:怎么看

判断只有一条主线:按批次上色要混匀,按已知 marker / 细胞类型上色要仍然分得开。 两者兼顾才算好。

# 一图两色对照:批次该混、生物学该留
DimPlot(obj, reduction = "umap", group.by = "batch")            # 期望:各批混匀
FeaturePlot(obj, features = c("CD3D", "MS4A1", "LYZ", "NKG7"))  # 期望:各群 marker 仍清楚

对着图判断三种状态:

现象UMAP / 聚类上的样子判断与对策
整合不足按批次上色,同类细胞仍被拆成各批次各一坨校正不够。换更「敢对齐」的方法(如 CCA)、或检查高变基因是否选偏
恰当按批次充分混匀,按 marker / 细胞类型仍清晰分开目标状态
整合过度本该分开的细胞类型 / 状态被并到一起;稀有群消失;marker 不再区分校正过头,抹掉了真实生物学。换更保守的方法(如 RPCA)、或减小对齐强度

几个要点:

  • 一定要拿已知的判别 marker 回验:找两个本应区分的细胞类型(比如 T 细胞的 CD3D 与单核的 LYZ),看整合后它们在图上是否还分得开。若被并到一起,就是过度整合的警报。
  • 稀有群最先受害:过度整合往往先把稀有细胞并进邻近大群。若您关心某个小群,整合前后都点它的 marker 数一数。
  • 也有定量指标——如 LISI(iLISI 看批次混合、cLISI 看类型纯度)、kBET、轮廓系数——可以把「混得够不够、纯不纯」量化。它们是有用的辅助,不是判决书:没有一个能套所有数据的硬阈值,仍要结合上面的看图与 marker 回验。
  • 「混匀」和「保留生物学」本质是一对矛盾,越使劲混批次,越容易连真差异一起混掉。整合的手艺就是在这条张力上找平衡,没有免费的午餐。

整合之后还能做差异吗

能,但别在整合 / 校正后的数据上做差异——这是最关键、也最常被踩的一条。

原因和散装数据里「去批次矩阵不能回喂差异分析」一模一样:整合改动过的值已经不是独立的原始观测,直接拿去做统计检验会低估方差、放大显著性。好在 Seurat v5 里,IntegrateLayers 各方法(Harmony / RPCA 等)只改低维嵌入、不改表达值,所以:

  • 整合后的降维integrated.rpcaharmony 等):只用来找近邻、聚类、画 UMAP,即「确定有哪些共享细胞类型」。
  • 差异分析:一律回到未整合的 RNA 表达(log 标准化后的 RNA assay)上做。
# 整合只改了坐标,没改表达。做差异先把拆开的 layer 合回来,并切回 RNA assay
obj <- JoinLayers(obj)
DefaultAssay(obj) <- "RNA"

# 在某一细胞类型内部,按分组比较
Idents(obj) <- "cell_type"
tcell <- subset(obj, idents = "T cell")
Idents(tcell) <- "condition"
de <- FindMarkers(tcell, ident.1 = "disease", ident.2 = "control")

再进一步,跨样本、跨条件的组间差异,更稳的是「伪散装(pseudobulk)」:把每个样本、每类细胞的 counts 加总成一条「散装」样本,再用 DESeq2 / edgeR 在样本层面做差异。这样把「样本」而非「细胞」当作重复单位,才不会因为把成千上万个细胞当独立样本而虚高显著性。

# 每个 sample × cell_type 汇总为一条伪散装,再走标准差异分析
pb <- AggregateExpression(obj, assays = "RNA", return.seurat = TRUE,
                          group.by = c("sample", "cell_type"))
# 之后按 condition 用 DESeq2 做差异,阈值常用 padj < 0.05,是惯例、按需收紧
  • 单细胞逐细胞检验(如 FindMarkers 默认的 Wilcoxon)适合在样本内看某群 vs 其余;跨条件比较时优先考虑伪散装。取舍见 统计方法怎么选
  • 差异基因拿到手,接着常做富集看落在哪些通路,见 富集分析怎么做

在平台上跑一遍

不想在本地装 Seurat、harmony、折腾 v5 的 layer,也能完成整套整合:在 百沐一下 上传多样本单细胞数据(或多个矩阵 + 标注了样本 / 批次的信息表),用一句话说清目的——例如「把这几份样本做批次整合再统一聚类注释,物种是人,然后比较 disease vs control」,平台会零代码替您跑整合、给出按批次和按细胞类型上色的对照 UMAP、提示整合是否过度或不足,并在差异分析时自动回到未校正表达 / 用伪散装,连同可复现的 R 代码一起交付。用法见 组学分析助手使用指南

相关