数据准备:输入数据格式要求

做ComBat校正,最磨人的往往不是算法本身,而是数据准备。我见过太多人把时间花在调参上,结果数据格式一塌糊涂,跑出来的结果根本没法用。说白了,这一步要是没搞对,后面全是白干。

这一章我们就来聊聊,ComBat到底需要什么样的输入数据。别小看这个,格式对了,后面的活儿能省下一半时间。

核心输入:基因表达矩阵

ComBat的核心输入就是一个矩阵。你可以把它想象成一张大表——行是基因(或者探针、蛋白、代谢物),列是样本。

我个人习惯把表达矩阵存成一个CSV或TSV文件,行名是基因名,列名是样本名。举个例子:

Gene_Symbol,Sample1,Sample2,Sample3,...
TP53,12.3,11.8,15.2,...
BRCA1,8.9,9.2,7.5,...
EGFR,5.6,5.1,6.8,...
...

关键点看这里:

  • 数值类型必须是连续型——像是log2表达量、FPKM、TPM这些都行。计数数据(比如原始read count)就别直接往里扔了,ComBat是为连续数据设计的。
  • 不要有空值——我曾经一次项目里,有个基因在某个批次里全是NA,ComBat直接报错。后来我用均值补了,结果还是把那个批次搞得一塌糊涂。所以要么补全,要么删掉。
  • 数据最好已经做过标准化——ComBat不负责帮你归一化。我建议至少做完log2转换或quantile normalization再输入。

批次标签:怎么告诉ComBat哪个样本属于哪个批次

表达矩阵之外,你还得给出一份批次标签信息。说白了就是一张“样本-批次对照表”。

格式大概是这样的:

Sample_ID,Batch
Sample1,Batch1
Sample2,Batch1
Sample3,Batch2
Sample4,Batch2
Sample5,Batch3
...

你想想看,如果这个表搞错了,比如样本2和样本3的批次标反了,ComBat会做什么?它会错误地把批次间的差异当成真实生物学变异去校正,结果就是你把好的数据洗坏了。

我个人习惯的做法是:在准备数据阶段,先画一个箱线图或者PCA图,看看样本是否真的按批次聚类。如果肉眼都能看出批次效应,那这个标签大概率是对的。

特征注释(可选但推荐)

ComBat还有一个进阶输入——特征注释。这个不是必须的,但我建议你加上。

典型用途是:你想告诉ComBat,“这批探针是基因,那批探针是对照,校正时不要把对照弄乱了”。

格式同样简单:

Probe_ID,Type
A_01_P000001,gene
A_01_P000002,gene
A_01_P000003,control
...

如果不提供这个,ComBat默认把所有特征当成一类来校正。大多数场景下这没问题,但如果你手上有对照探针或spike-in,那就别省这一步了。

数据质量要求:别拿垃圾数据糊弄ComBat

嗯,这里要注意:ComBat不是魔法。你再好的算法,输入一堆垃圾数据,结果也是垃圾。

数据底线要求:

  • 每个批次至少要有3个样本(越多越好,我建议每个批次至少5个)
  • 不能有全零行或全NA行
  • 数据分布不要严重偏态(比如未log2的原始count数据)
  • 不同批次间的基因数量必须一致

我曾经在一个多中心项目中遇过——某个中心只提供了2个样本。ComBat跑是能跑,但校正完这批样本就像被“吸”到了其他批次一样,完全失真了。所以2个样本的批次,要么合并到其他批次,要么就直接剔除吧。

一张图看清整个数据准备流程

下面这个SVG图总结了数据准备的关键节点和它们之间的关系:

数据准备核心流程 基因表达矩阵 行=基因,列=样本 批次标签表 样本→批次映射 特征注释(可选) 探针类型,基因/对照 数据质量检查 连续值?无空值?批次样本≥3?特征数一致? 预处理(log2转换/归一化) ComBat 输入就绪 注意:如果输入数据存在批次内部缺失值,考虑使用均值或KNN插补, 切勿直接删除整行整列,以免影响批次校正结果

常见数据格式问题排查

我把这些年在项目中踩过的坑整理了一下,做成一个速查表,你直接对着检查就好:

问题类型 表现 我的处理方式
基因名重复 同一基因多行,ComBat报错 取均值或中位数合并,或按表达量保留最高的一行
样本名与批次表不匹配 ComBat运行后样本顺序错乱 强制对齐:match(colnames(expr), batch$Sample_ID)
批次标签是数值 ComBat把批次当成连续变量处理 转为因子:batch$Batch <- as.factor(batch$Batch)
表达矩阵有负值 部分模型参数计算异常 检查是否做过log2转换,某些归一化会残留负值

一个小技巧:

在把数据喂给ComBat之前,先做一个dim(expr)和table(batch),确认维度一致,批次样本数合理。这个习惯救了我好几次。

代码里的数据格式示例

如果你用R,最经典的方式是这样读取数据:

# 读取表达矩阵
expr_matrix <- as.matrix(read.csv("expression_data.csv", row.names = 1))

# 读取批次信息
batch_info <- read.csv("batch_labels.csv")
batch_info$Batch <- as.factor(batch_info$Batch)

# 检查样本顺序是否一致
all(colnames(expr_matrix) == batch_info$Sample_ID)
# 如果不一致,就重新排序
batch_info <- batch_info[match(colnames(expr_matrix), batch_info$Sample_ID), ]

如果你用Python,通常是用pandas处理:

import pandas as pd
# 读取表达矩阵
expr_df = pd.read_csv("expression_data.csv", index_col=0)
# 读取批次信息
batch_df = pd.read_csv("batch_labels.csv")
# 按样本名对齐批次标签
batch_series = batch_df.set_index("Sample_ID").loc[expr_df.columns, "Batch"]

代码本身没什么高深的,但样本顺序对齐这一步,我至少见过5个人在这上面翻车。ComBat对输入顺序敏感——批次标签的顺序必须和表达矩阵的列顺序严格一致。

嗯,说到这里,其实数据准备的核心就这些了。总结一下就是:表达矩阵+批次标签+特征注释(可选),格式要对,顺序要对,质量要对。做到这三条,ComBat就能跑得很顺畅。