3、数据预处理:标准化、归一化、缺失值处理
数据预处理这个环节,说实话很容易被大家跳过去。我刚入行时也觉得“原始数据直接扔进模型不就好了?”,结果第一次跑批次效应校验,出来的结果乱成一锅粥。后来才明白——数据预处理不是可选项,是必选项。你想想看,不同平台、不同时间点测出来的表达量,量纲都不一样,怎么直接比?
这一章我们就把标准化、归一化和缺失值处理这三个基础动作讲透。掌握了它们,后续的批次效应校验才能站得住脚。
标准化(Z-score)——消除量纲差异
标准化的核心思路是让每个特征变成均值为0、标准差为1的分布。说白了,就是把数据“拉”到同一把尺子上。
公式很简单:z = (x - μ) / σ。我习惯在批次效应校验之前,先对所有样本的表达矩阵按基因做标准化。为什么要按基因?因为同一个基因在不同批次里的分布差异才是我们关心的。
代码实现推荐用scikit-learn的StandardScaler:
from sklearn.preprocessing import StandardScaler
import pandas as pd
# 假设 df 是表达矩阵,行为样本,列为基因
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df),
index=df.index,
columns=df.columns)
归一化(Min-Max)——缩放到 [0,1] 区间
归一化和标准化不同,它把数据压到0到1之间。公式:x_norm = (x - min) / (max - min)。
什么时候用归一化?当你的后续算法对尺度敏感,比如神经网络、KNN、PCA,而且你知道特征的最大最小值是合理的边界时。我自己的习惯是:如果做可视化(比如热图、t-SNE),优先用归一化,颜色映射更直观。
用MinMaxScaler轻松搞定:
from sklearn.preprocessing import MinMaxScaler
scaler_mm = MinMaxScaler()
df_norm = pd.DataFrame(scaler_mm.fit_transform(df),
index=df.index,
columns=df.columns)
标准化 vs 归一化 怎么选?
| 场景 | 推荐做法 |
|---|---|
| 批次效应校验(ComBat等) | 标准化(Z-score) |
| 热图、相关性图 | 归一化 |
| 距离计算(欧氏距离) | 标准化 |
| 不保证分布正态 | 优先归一化 |
缺失值处理——不补不行,补法有讲究
真实数据里缺失值几乎是逃不掉的。我遇到过一张表达矩阵,30%的基因都有缺失。当时试过直接删行,结果样本量掉了一半——不行。后来我总结了一套处理流程。
第一步:判断缺失类型
- 完全随机缺失(MCAR)——可以简单插补或删除
- 随机缺失(MAR)——需要考虑辅助变量
- 非随机缺失(MNAR)——比较麻烦,需要领域知识
第二步:选择策略
常用方法有:
- 删除法:直接删掉缺失比例超过阈值的基因或样本。阈值我一般设20%,因为超过这个比例后插补结果可能失真。
- 均值/中位数填充:简单但粗暴。我把它当基线,对比其他方法。
- KNN插补:利用最近邻样本的值来填充,效果通常比均值好。但计算量大,数据量大时慎用。
- 迭代回归插补(MICE):多次回归+随机噪声,处理复杂缺失模式很有效。
代码示例:
import pandas as pd
from sklearn.impute import KNNImputer
# 构建示例数据
data = pd.DataFrame({'gene1': [1.2, 2.4, None, 3.1],
'gene2': [0.5, None, 2.0, 1.8]})
# KNN插补(k=3)
imputer = KNNImputer(n_neighbors=3)
data_imputed = pd.DataFrame(imputer.fit_transform(data),
columns=data.columns)
数据预处理整体流程
把上面三件事串起来,我一般这样走:先做缺失值处理,再做归一化或标准化,最后检查分布。下面这张图帮你理清逻辑:
df.describe()瞄一眼,确保没搞反。
常见的三个坑
- 坑一:先标准化再插补——标准化后的均值为0,缺失值填充成0会造成严重偏差。正确顺序是:先插补,再标准化。
- 坑二:全表统一归一化——如果批次之间本身就有系统偏移,统一归一化会把真实差异压缩掉。应该按批次分别做归一化。
- 坑三:忽略缺失模式——全部填充均值,可能导致分布变形。我习惯先画缺失值热图,看看是否集中在某些基因或样本。
好了,数据预处理讲到这里。核心就是三件事:填缺、调尺度、检查。下一环节我们就可以拿着干净的矩阵去做批次效应校验了。