4. 数据预处理
数据预处理,说实在的,是DIABLO建模里最容易被低估的一步。我见过不少团队,模型选得花里胡哨,结果因为数据没处理好,跑出来的结果一塌糊涂。你想想看,输入的是垃圾,输出当然也是垃圾。多组学数据来自不同平台,量纲、分布差异巨大,不统一处理,模型根本没法正常工作。
4.1 为什么预处理如此关键?
DIABLO的核心,是从多个组学视图里提取共享的低维结构。这要求每个视图的数据分布不要过于离谱。举个例子,转录组数据通常是count值,范围从0到几万;而代谢组数据可能是峰面积,或者已经归一化过的相对丰度。把这两种数据直接塞进模型,高量纲的变量会主导距离计算和协方差结构。
我习惯把预处理的目标归结为三点:
- 消除平台差异 – 让不同组学的变量具有可比性
- 稳定方差 – 尤其是高表达基因通常会方差更大,需要控制
- 去噪与质量控制 – 剔除低质量的样本和特征,不让它们带偏模型
4.2 归一化 vs 标准化 – 别搞混了
这两个概念经常被混用,我来理清楚。
| 方法 | 公式 | 结果范围 | 适用场景 |
|---|---|---|---|
| Min-Max 归一化 | (x - min) / (max - min) | [0, 1] | 当数据已有明确上下界,或后续要用到距离度量 |
| Z-score 标准化 | (x - mean) / sd | 均值为0,标准差为1 | 数据近似正态,或后续需要协方差结构 |
| 总和归一化 | x / sum(all) | [0, 1] 且总和为1 | 测序深度归一化常用(如CPM) |
DIABLO底层用的是偏最小二乘的思想,它本质上对数据的尺度比较敏感。我个人倾向于先做Z-score标准化,让每个变量都在同一水平上。但有一种情况例外:如果数据里包含大量零值(比如稀疏的微生物组数据),Z-score会放大那些零点的噪声。这时候我会先用log2转换,再做标准化。
4.3 log2转换 – 为什么是2不是10?
log转换的核心目的,是让数据分布更接近正态,同时让方差与均值解除关联。你想想看,表达量10000的基因,随机误差可能是几百;而表达量10的基因,误差可能只有1。直接在原始尺度上建模,高表达变量会在协方差矩阵里称王称霸。
为什么选log2?两个原因:
- 生物学上,fold change以2倍为单位,log2之后差异可以直接解读为倍数变化
- 计算上,log2转换后,均值和方差更容易处理
常见的做法是,对count类数据做log2(CPM + 1)或者log2(FPKM + 1),加1是为了避免log(0)的问题。代谢组数据如果已经是相对丰度,也可以直接log2转换。
# R语言示例:用edgeR做log2转换
library(edgeR)
# 假设count_matrix是基因表达计数矩阵
dge <- DGEList(counts = count_matrix)
dge <- calcNormFactors(dge)
cpm_matrix <- cpm(dge, log = TRUE, prior.count = 1)
# 结果就是log2(CPM + 0.5)或log2(CPM + 1)
# 具体取决于prior.count参数
你可能会问:为什么不log10?其实都可以,只是log10之后解读差异没那么直观。我在项目中统一用log2,方便后续做fold change分析时直接对应。
4.4 数据质量控制 – 坏数据会毁掉模型
这一步我建议放在所有处理的最前面。先做QC,选好样本和特征,再去做归一化和转换。否则垃圾数据经过转换,看起来规整了,但本质还是垃圾。
QC主要做两件事:
- 样本层面:
- 缺失率:某个样本缺失超过30%的特征,直接删除
- 离群值:用PCA或者层次聚类看是否有明显的离群样本
- 批次效应:如果数据来自不同批次,先用ComBat或limma矫正
- 特征层面:
- 低表达过滤:转录组中平均CPM小于0.5的基因,大概率是噪声
- 缺失率:某个特征在超过50%的样本中缺失,删掉
- 方差过滤:方差接近于0的特征对模型没有信息贡献
# R语言示例:特征过滤与样本QC
# 使用mixOmics包中的数据(diablo示例数据)
# 加载数据
data("breast.TCGA")
X <- breast.TCGA$data.train
# 特征缺失率过滤
filter_features <- function(mat, threshold = 0.5) {
missing_rate <- apply(mat, 2, function(x) sum(is.na(x)) / length(x))
keep <- missing_rate <= threshold
message(paste("保留", sum(keep), "个特征,删除了", sum(!keep), "个"))
return(mat[, keep])
}
# 样本缺失率过滤
filter_samples <- function(mat, threshold = 0.3) {
missing_rate <- apply(mat, 1, function(x) sum(is.na(x)) / length(x))
keep <- missing_rate <= threshold
message(paste("保留", sum(keep), "个样本,删除了", sum(!keep), "个"))
return(mat[keep, ])
}
# 执行过滤
X_filtered <- filter_samples(X)
X_filtered <- filter_features(X_filtered)
4.5 完整预处理流程 – 我一般这么做
下面是我在项目里常用的三步走流程。当然,具体细节会根据数据类型微调,但大方向不变。
- QC过滤:删除低质量样本和特征
- 归一化:测序数据用CPM/TPM,代谢组数据用总和归一化或PQN
- log2转换 + Z-score标准化:先log2,再Z-score,最后整合
# 完整预处理示例(R语言)
preprocess_diablo <- function(mat_list, qc_threshold = 0.5) {
# 假设mat_list是一个命名列表,每个元素是一个组学矩阵
processed <- list()
for (name in names(mat_list)) {
mat <- mat_list[[name]]
# 步骤1: 样本QC - 删除缺失过多的样本
sample_na <- apply(mat, 1, function(x) sum(is.na(x))/length(x))
mat <- mat[sample_na < 0.3, ]
# 步骤2: 特征QC - 删除缺失过多的特征
feature_na <- apply(mat, 2, function(x) sum(is.na(x))/length(x))
mat <- mat[, feature_na < qc_threshold]
# 步骤3: 低表达过滤(针对转录组)
if (name == "mrna") {
expressed <- apply(mat, 2, function(x) sum(x >= 10)) >= 0.5 * nrow(mat)
mat <- mat[, expressed]
}
# 步骤4: 归一化(用总和归一化作为示例)
mat <- sweep(mat, 1, rowSums(mat, na.rm = TRUE), "/") * 1e6
# 步骤5: log2转换
mat <- log2(mat + 1)
# 步骤6: Z-score标准化
mat <- scale(mat)
processed[[name]] <- mat
}
return(processed)
}
4.6 知识体系一览
下面的SVG图梳理了本章的核心逻辑,从原始数据到DIABLO输入,中间的每一步都有对应的决策点。你可以拿它当一个工作流检查清单。
4.7 不同组学数据的预处理策略
每一种组学都有它自己的"脾气",不能一刀切。我整理了一下常见的处理方式:
| 组学类型 | 原始数据形式 | 推荐归一化 | QC关注点 |
|---|---|---|---|
| 转录组(RNA-seq) | count矩阵 | CPM / TPM / FPKM | 低表达基因、批次效应 |
| 代谢组(LC-MS) | 峰面积 | 总和归一化或PQN | 缺失值、批次漂移 |
| 蛋白质组 | iBAQ / TMT ratio | 中位数标准化或IRS | 缺失比例、定量准确性 |
| 微生物组(16S) | OTU/ASV count | CSS / TMM / 稀有化 | 稀疏性、测序深度 |
你看这张表,右边几列都不是固定的。比如代谢组数据,如果样本量小且缺失率高,可以先做缺失值填充(用kNN或者半最小值),再做归一化。蛋白组数据如果来自TMT标记实验,还得考虑通道效应。
4.8 总结一下
数据预处理听起来琐碎,但它在DIABLO流程里的分量,真的不亚于模型本身。你想想看,原始数据带着不同量纲、不同分布、不同噪声水平直接进去,模型的第一主成分很可能就被某个高方差变量垄断了,那多组学整合的意义就全没了。
我的建议是:先把QC做到位,剔除那些明显有问题的样本和特征;然后根据组学类型选合适的归一化方法;最后统一做log2转换加Z-score标准化。这样处理之后,不同组学视图的数据才算真正"对齐"了,模型才能从生物学信号里学到东西。
嗯,这章内容我们先到这里。把预处理功底打扎实,后面建模的事就好办了。