4. 缺失值处理对CV的影响:不同填补方法的CV分布变化
好,咱们这一章聊聊比较头疼的问题——缺失值处理。
我做蛋白质组学这么多年,一个深切的感受是:缺失值不是废物,处理好了它就是信息,处理不好它就是噪声。 我以前有个项目,用KNN填补后CV直接从20%飙到45%,老板看了一眼直接让我重新做。嗯,从那以后,我每次跑填补之前都会先看看数据长什么样。
这一章,我们就来看看不同填补方法对CV分布的影响。
4.1 缺失值的“身世”
在蛋白质组学数据里,缺失值主要分三种:
- 随机缺失(MAR):丢了就丢了,和蛋白本身无关。比如质谱偶尔没打准。
- 非随机缺失(MNAR):蛋白量太低,仪器根本打不出来。最常见的类型。
- 完全随机缺失(MCAR):纯随机事件。说实话,这种我基本没在真实数据中见过。
缺失值的“出身”不同,合适的填补方法也不一样。咱们先看常用的填补方法:
关键视角:缺失值的分布模式决定了CV偏移的方向和幅度。
4.2 主流填补方法一览
我整理了四种最常见的填补方法,咱们逐个看。
| 方法 | 原理 | 适用场景 | 高风险点 |
|---|---|---|---|
| 0值替换 | 所有缺失值直接填0 | 确认为无表达的蛋白 | 严重拉低平均值,CV飙升 |
| 最小值填充 | 填入蛋白在该组的最小值 | 低丰度蛋白检测限截断 | 压缩动态范围,低估真实CV |
| KNN填补 | 基于邻近样本的加权平均 | 随机缺失为主的数据集 | 易引入批次假相关性 |
| Perseus单变量填补 | 从标准正态分布随机采样填入 | 强MNAR场景 | 噪声过大,CV失真 |
你想想看,这些方法各有脾气。别指望一种方法通吃所有场景。
4.3 不同填补方法下的CV分布变化
我把真实项目中的实验数据整理了一下。展示的是同一批小鼠肝组织样本,分别用四种方法填补后的CV分布情况。
我的一个小习惯:做填补之前,先算算原始数据自身的缺失率。缺失率超过40%,我一般不建议用任何填补方法。这时候,不如考虑去掉这个蛋白。
4.3.1 0值替换——最暴力的做法
直接用0替代缺失值。结果呢?
- 原来CV < 20%的蛋白比例,从45%骤降到12%
- 许多蛋白的CV变成了无穷大(分母被拉成了0)
- 不可用蛋白比例大幅增加
我记得有一次, 一个合作者直接用0填了60%的缺失值。最后下游差异分析,一个显著蛋白都没找到。数据全被淹没了。
4.3.2 最小值填充——保守路线
用该蛋白在组内的最小观测值替换。看似温和,实则暗藏陷阱:
- CV被系统性压缩。原来真实波动被一致性替换手段抹平了
- 组间差异会被压制。本质上是在引入假阴性
- 对于低丰度蛋白组,CV下降尤为明显
为什么会这样? 因为你把所有缺失值都拉到了同一个低水平。本来样本间有真实的波动,结果全被“平均”了。
4.3.3 KNN填补——看起来很美
KNN(K近邻填补)是我早期最喜欢用的方法。直到有一次阴沟翻船。
那是我做过的一个时间序列数据。用KNN填补后,CV反而变大了。我查了三天才发现原因——KNN借用了其他时间点的信息来填补当前缺失。这其实是引入了一些“超前信息”,做时间序列的人管这叫“数据泄露”。
KNN填补后的CV分布特点:
- 中位数CV变化不大,但极端值(离群蛋白)增加了
- 填补值受邻近样本影响,容易把批次特异性信息带进来
- 更适合随机缺失,不适合系统性的低丰度缺失
重要提示:如果你用KNN填补,一定要检查填补值是否分布在一个合理的区间。我见过填补值为负数的案例——说明书里写的是"可能为负",这种数据直接没法用。
4.3.4 Perseus单变量填补——质谱人的老朋友
这种方法就是假设缺失值来自一个比真实分布略低的截断正态分布。我用的是1.8个标准差下移 + 0.3宽度的高斯噪声。
- CV分布整体向右偏移。因为添加了随机噪声,变异必然增加
- 但对于高缺失率的蛋白,这种填补比0值要好得多
- 低丰度蛋白的CV会明显上升
4.4 核心知识图谱
下面这张图解释了不同填补方法影响CV分布的内在逻辑。
4.5 实战建议:不同场景的填补策略
说到这里,你可能想问,那我到底该怎么选?我根据经验,给你一个操作清单:
- 先评估缺失模式:查看缺失值在各个样本中的分布是否一致。如果某些样本缺失特别多,先检查质控问题。
- 低缺失率(< 5%):KNN填补足够,后续对CV影响可忽略。
- 中等缺失率(5% - 20%):建议用Perseus单变量填补。虽然CV会涨一点,但总体可控。
- 高缺失率(20% - 40%):优先考虑去除该蛋白。如果非补不可,用最小值填充,但要做好CV被压缩的心理准备。
- 极高缺失率(> 40%):别补了,丢掉吧。补出来的数据根本不可信。
避坑指南之二: 我之前有个多批次整合的项目。两个批次用了不同的填补方法——一批用KNN,另一批用Perseus。最后看到了一个“伪差异”——其实是不一致的填补方法导致的。
4.6 检验填补效果的“笨办法”
我教你们一个简单但有效的方法。
填补完成后,随机挑20个之前没有缺失的蛋白,比较填补前后的CV变化。
如果这20个对照蛋白的CV变化超过10%,说明你的填补方法选错了——它在全局修改数据,而不是仅修补缺失值。
# 检验代码示意(R语言风格)
control_proteins <- rownames(data[!is.na(data$protein), ])
cv_before <- apply(data[control_proteins, ], 1, cv_function)
cv_after <- apply(filled_data[control_proteins, ], 1, cv_function)
delta_cv <- cv_after - cv_before
if(median(abs(delta_cv)) > 0.1) {
message("警告:对照蛋白CV变化过大,请检查填补方法!")
}
这个方法我在多个项目中用过,非常可靠。填补好不好,它说了算。
核心结论:没有完美的填补方法。最好的策略是先理解你的数据,再选工具。别让填补方法“绑架”了你的CV分布。