4. 常用批次校正方法介绍:ComBat、Harmonization 等

说到批次校正,我最早接触的是基因表达芯片数据,当时不同批次间的差异大到能让你怀疑人生。你以为找到的生物标志物,其实只是批次效应。后来做 ADMET 预测,同样的化合物换个实验室测,结果直接漂移一个数量级。嗯,批次校正不是「锦上添花」,是「不做就完蛋」。

这一章咱们就聊聊几个主流的批次校正方法。我自己的项目经验里,ComBat 和 Harmonization 是出场率最高的两位主角,它们背后原理不一样,调参重点也不同。你会看到有人直接跑默认参数就信了结果——我劝你别这么干。

4.1 ComBat:贝叶斯框架下的老兵

ComBat(Combining Batches)最初是生信圈为了整合基因芯片数据搞出来的,后来被我们做 ADMET 的顺手拿来用。它的核心思路是:对每个特征(比如 logD, 清除率),建立线性模型,将批次均值和方差分别做贝叶斯调整。

公式我就不全列了,你记住两个关键参数就好:

  • prior.plugs(或 Python 版的 prior_std 等):控制先验强度。值越大,校正后批次之间越「平滑」,但可能抹掉真实生物学信号。我调过一个清除率预测项目,把 prior.plugs 从 0.5 改到 2,RMSE 直接降了 8%——但小心,那也可能是在过校正。
  • 非参数模式(nonparametric):当批次内样本数太少(比如少于 5),参数估计会崩。这时候走非参数版本会更稳。

下面是一个我在 R 中常用的 Combat 调用,配合一点调参建议:

library(sva)
# edata: 特征矩阵 (特征 x 样本)
# batch: 批次标签向量
# mod: 协变量矩阵 (如年龄、性别,ADMET中常放化合物结构指纹PC1等)
adjusted <- ComBat(
  dat = edata,
  batch = batch,
  mod = mod,
  par.prior = TRUE,       # TRUE用参数先验,FALSE用非参数
  prior.plots = FALSE,    # 先验图,调试时可以打开看看
  mean.only = FALSE       # TRUE只校正均值,方差不变
)
我踩过的坑:mod 里不要把批次标签放进去,否则模型会偷看批次信息导致校正无效。另外,如果你只有两个批次,ComBat 默认用先验可能过于保守,可以考虑用 mean.only = TRUE 先试一版。

4.2 Harmonization(NeuroCombat):线性混合模型路线

Harmonization 家族(像 NeuroCombat)本质上是 ComBat 的变体,但引入了线性混合模型(LMM),对协变量的处理更灵活。举个例子,当你需要保留 dataset 间的协变量效应(比如两种不同的 ADMET 测定平台)时,Harmonization 能显式建模随机截距和随机斜率。

我个人在跨平台代谢稳定性数据校正时试过 NeuroCombat 的 Python 实现,对比原版 ComBat,它的优势体现在:

  • 对样本量极不平衡的批次(比如 A 批次 1000 个,B 批次 3 个)更鲁棒。
  • 可以处理连续型协变量(比如实验日期,温度)与非线性的批次关系。

调用方式(Python 版 neurocombat):

from neurocombat import combat as neurocombat
# data: 样本 x 特征的 numpy 数组
# batch: 批次列表
# mod: 包含协变量的矩阵,第一列通常为截距
adjusted = neurocombat(
    data = data.T,          # neurocombat 要求特征 x 样本
    batch = batch_vector,
    mod = covariate_matrix,
    eb = True,              # Empirical Bayes 开关
    parametric = True       # 参数先验
).T                         # 转回样本 x 特征
我曾经在 5 个批次、12 个化合物的小数据集上直接跑 NeuroCombat 默认参数,校正后其中一个化合物的 logD 值被拉到异常区域。后来发现是 eb = True 在小样本下先验估计失真。改成 eb = False(等同于固定效应)才正常。所以,小批次数据(总样本 < 30)我建议先关掉 Empirical Bayes。

4.3 其他常用方法一览

除了 ComBat 和 Harmonization,你还会在实际项目中遇到:

方法适用场景优点缺点
limma(线性模型+经验贝叶斯)微阵列或小样本 ADMET实现简单,统计检验成熟不能显式校正方差,只做均值校正
PCA/ICA 去批次可视化、降维后分析直观,不需要批次标签可能混入生物学变异,谨慎使用
Per-batch Z-score快速审核,粗筛零参数,几行代码搞定只调整均值和方差,无法保留批次间结构差异
MNN(互近邻)单细胞或多模态数据处理复杂批次结构对 ADMET 多批次整合计算量大

说实话,Per-batch Z-score 是我在临时检查时最常用的——用一行 (x - mean(x)) / sd(x) 就够了。但它只能作为基线,正式建模时我几乎不用。

4.4 方法选择的核心逻辑图

为了帮你快速决策,我画了一张流程框架图。你可以直接对照自己的数据情况走一遍:

批次校正方法选择决策树 原始多批次数据 批次数量 ≥ 3? 是 → 否 → 样本量均衡? ComBat 非参数 Harmonization 校正后必须验证 评估:PCA/箱线图/RSD 小样本 (n ≤ 5/批次) 建议强制关掉 EB 先验
核心原则:不要依赖单一方法。我一般会先用 ComBat 参数模式 + Harmonization 跑两个版本,然后对比校正前后 PCA 图上批次间的分离程度。如果两者都让批次混在一起了,选验证集 RMSE 更低的那个。

4.5 避坑指南:我翻过的车

  • 把验证集也一起校正了:这是最经典的错。记得先在训练集上拟合成份(先验参数),然后用同一组参数转换验证集。我见过有人直接对整个数据集做 ComBat,然后做交叉验证——结果指标虚高得像假药。
  • 忽略协变量中的实验设计:比如你研究的是肝微粒体 vs 肝细胞,两种基质本身就有差异。如果在 mod 里不放这个因子,ComBat 会把生物学差异也当批次去掉。你想想看,最后模型对真实基质差异的预测能力就没了。
  • 对离散值过分校正:ADMET 数据里的异常值(比如清除率为 0.001),校正后可能被拉回正常范围。但你得先确认那个值是不是测量错误。我自己的做法是先做 Winsorize 再跑校正,不行再去看原始记录。

4.6 小结

ComBat 和 Harmonization 是目前批次校正的黄金搭档。ComBat 适合 3 个以上且样本量相对均衡的批次,Harmonization 在处理高度不平衡或含有复杂协变量时更灵活。别忘了,方法选得再好,不验证就是白做。我个人习惯是:校正完成后,立即画 PCA 散点图 + 计算每个特征的批次内 RSD 中位数。如果 RSD 中位数比校正前下降了 30% 以上,才算初步通过。