第4章 质谱数据预处理:基线校正、平滑、峰检测基础

拿到原始质谱数据,你千万别急着直接往上扔模型。原始数据又脏又乱,基线漂移、噪声干扰、峰形畸变,这些问题不处理,特征质量肯定打折扣。我在这个环节吃过不少亏,一开始总觉得预处理是浪费时间,后来发现——偷懒的代价就是模型精度上不去。

这一章,我们聚焦三步核心操作:基线校正、平滑、峰检测。这三步做好了,后续的特征提取才有意义。

4.1 基线校正:把地板找平

质谱的基线,并不是一条平直的线。它往往会随着时间或质量数缓慢漂移。为什么?原因很多:样品基质效应、色谱柱流失、检测器温度波动……说白了,你看到的信号是“真实峰 + 一个低频的干扰信号”。

我个人习惯用以下三种方法,按场景选:

方法 核心思想 我的使用场景
TopHat 变换 形态学操作,用结构元素腐蚀再膨胀,减掉背景 MALDI-TOF 数据,峰宽差异大的情况
多项式拟合 对非峰区域(噪声段)拟合低阶多项式,减去拟合曲线 LC-MS 连续谱,基线缓慢变化时
局部最小值法 滑动窗口取最小值,插值成基线 低分辨率数据,峰比较稀疏时
我的小技巧:不管用哪种方法,基线校正后一定要看一眼结果的尾部。我曾经遇到过多项式阶数太高导致在谱图两端出现“翘起”,把一些弱峰都给减没了。做基线校正时,宁可欠校正(留一点斜坡),也别过校正。

举个 Python 实现片段,TopHat 变换用 scipy 就能做:

from scipy.ndimage import white_tophat
import numpy as np

# spectrum: 原始谱图向量,structure: 结构元素(圆形或方形)
structure = np.ones(int(peak_width))  # 结构元素宽度根据峰宽估算
baseline_corrected = spectrum - white_tophat(spectrum, structure=structure)

注意这个 peak_width 参数。设小了,基线校正不彻底;设大了,可能把窄峰当作基线给减掉。我记得第一次用 MALDI-TOF 数据时没调这个参数,结果几个重要的代谢物峰直接消失了……排查了好久才找到原因。

4.2 平滑:跟噪声说拜拜

基线校完之后,谱图里仍高频噪声还在。这些噪声会让峰检测产生大量假阳性。我的目标很简单:去掉噪声,同时尽量保留峰的边缘信息。

两张主流“武器”:

4.2.1 移动平均平滑

简单粗暴,计算窗口内均值。优点是快,缺点是把峰也抹平了。我一般只在快速预览数据时用。

4.2.2 Savitzky-Golay 滤波

这才是正解。它在窗口内用多项式拟合中心点的值,能在平滑的同时较好地保持峰高和峰宽。你想想看,如果你用普通均值,峰尖肯定被砍矮,而 SG 滤波能避免这个问题。

from scipy.signal import savgol_filter

# window_length 必须是奇数,polyorder 建议 2 或 3
smoothed = savgol_filter(spectrum, window_length=11, polyorder=2)
注意:window_length 越大,平滑越强,但峰形失真也越严重。polyorder 不要超过 5,否则会产生不必要的振荡。我做过测试——polyorder=5 加 window_length=21 时,一些低丰度峰会被“削平”变成伪特征。

4.3 峰检测:找真正的信号

基线校了,噪声也压了,接下来就是找峰。峰检测听着简单,但陷阱不少。我总结的核心三要素:峰位置(质荷比)、峰强度、峰边界。

常用方法我列了个表:

方法 原理 我的推荐值
阈值法 信号超过某个信噪比阈值(如 SNR > 3) SNR 阈值设为 3~5,噪声水平用 MAD 估计
导数法 一阶导过零点 + 二阶导负值判断峰顶 适合基线干净的谱图
匹配滤波器 用高斯或洛伦兹模板与信号做卷积 峰形已知时效果好,比如 TOF 数据

下面是我常用的一段峰检测代码,基于 scipy.signal:

from scipy.signal import find_peaks

peaks, properties = find_peaks(
    smoothed,
    height=noise_level * 3,     # 高度阈值(SNR=3)
    distance=5,                 # 峰之间最小间隔(点数)
    prominence=0.5,             # 峰相对周围的最小凸起
    width=(2, 20)               # 峰宽范围(点数)
)
关键参数解读:
  • prominence(显著度)—— 我最看重的参数。它能防止把基线波动误判为峰。建议根据谱图噪声水平调一个经验值。
  • distance(最小距离)—— 防止同一个峰被检测成两个。如果你在数据里看到一堆“双子峰”,八成是这个参数设小了。
  • width(峰宽范围)—— 我觉得这个参数特别有用。设一个合理的范围,能把那些太尖(可能是噪音)或太宽(可能是基线隆起)的假峰过滤掉。

4.4 峰合并与去卷积

实际数据里,一个峰可能对应多个同位素峰或共流出物。这时候需要做峰合并或者去卷积。

我常用的策略是:先做基本峰检测,然后对 m/z 距离在某个容忍度(例如 0.01 Da 或 10 ppm)内的峰进行合并,保留强度最大的那个或者求和。在 LC-MS 数据中,我习惯用 0.01 Da 的容忍度来合并同位素峰簇。

避坑指南:我曾经在低质量分辨率数据中用过 0.5 Da 的合并窗口,结果把相邻的 m/z 峰全部吞并了,后面做特征关联时一团糟。记住——合并窗口要跟你仪器的质量精度匹配,不是越大越好。

4.5 完整流程的 SVG 框架图

质谱数据预处理核心流程 原始质谱数据 步骤1:基线校正 TopHat 变换 | 多项式拟合 | 局部最小值法 步骤2:平滑去噪 Savitzky–Golay 滤波 | 移动平均 步骤3:峰检测 阈值法 | 导数法 | 匹配滤波 可选:峰合并(同位素/共流出) 干净特征谱 需要关注的点 • 基线校正不能过校正 • SG 滤波参数要调试 • prominence 是关键 • 合并窗口匹配精度
个人经验总结:我刚开始做质谱数据分析时,总想一步到位把峰检测参数调完美。后来发现,参数的意义是相对的,不是绝对的。最好的做法是:拿一小批手工标注的谱图,把预处理流程跑通,看着效果调参数,然后再批量处理。这一步值得多花时间——我以前试过全自动处理 500 份血清样本,结果有 30% 的数据基线校歪了,最后只能重新跑一遍。所以,先检查 5~10 条谱图,再全量运行,这是我现在的铁律。