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分布的内在逻辑。

不同填补方法影响CV分布的内在逻辑 原始缺失数据 非随机缺失 (MNAR) 随机缺失 (MAR) 完全随机缺失 (MCAR) 最小值填充 Perseus修补 KNN填补 均值/中位数替换 0值替换 局部最小填充 CV分布偏移 / 压缩 / 膨胀 下游分析决策依据 知识提示:同一种填补方法在不同缺失模式下,CV分布差异巨大。建议先做缺失模式评估再选方法。

4.5 实战建议:不同场景的填补策略

说到这里,你可能想问,那我到底该怎么选?我根据经验,给你一个操作清单:

  1. 先评估缺失模式:查看缺失值在各个样本中的分布是否一致。如果某些样本缺失特别多,先检查质控问题。
  2. 低缺失率(< 5%):KNN填补足够,后续对CV影响可忽略。
  3. 中等缺失率(5% - 20%):建议用Perseus单变量填补。虽然CV会涨一点,但总体可控。
  4. 高缺失率(20% - 40%):优先考虑去除该蛋白。如果非补不可,用最小值填充,但要做好CV被压缩的心理准备。
  5. 极高缺失率(> 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分布。