数据预处理与质量控制方法归纳总结

数据预处理,说白了就是给原始数据“洗澡”。我做了这么多年QSAR,见过太多因为数据脏导致模型翻车的案例。今天就把这套洗澡流程给大家掰开揉碎了讲清楚。

核心原则:坏数据进,坏模型出。预处理不是可选步骤,是必须项。

数据清洗——把明显有问题的数据筛掉

拿到数据第一件事,不是急着建模。你得先看看数据长什么样。我个人习惯先用描述性统计扫一遍,看看有没有明显不对劲的地方。

问题类型识别方法处理方式
缺失值统计每列的NA/NaN数量删除(<5%)、插补(5-20%)、标记(>20%)
重复样本基于SMILES或结构指纹去重保留活性值最极端的,或取平均
异常活性值Z-score > 3 或 IQR法检查原始记录,确认后删除或修正
结构解析错误RDKit解析失败手动检查SMILES,修复或丢弃
避坑:我曾经遇到过一批数据,SMILES看起来没问题,但用RDKit一解析就报错。后来发现是SMILES里混了中文字符。这种数据一定要用代码批量检查,肉眼看不出来。

要养成用脚本检查数据的习惯。下面是我常用的检查代码:

import pandas as pd from rdkit import Chem

df = pd.read_csv('training_data.csv')
# 检查缺失值
print(df.isnull().sum())

# 检查SMILES合法性
valid_smiles = df['smiles'].apply(lambda x: Chem.MolFromSmiles(x) is not None)
print(f'非法SMILES数目: {(~valid_smiles).sum()}')

# 检查重复
print(f'重复样本数目: {df.duplicated(subset=["smiles"]).sum()}')

缺失值处理——别让空缺影响判断

缺失值怎么处理?这得看情况。我个人把缺失值处理分成三类场景:

  • 轻度缺失(<5%):直接删除,最简单粗暴,影响也不大
  • 中度缺失(5-20%):用插补法。数值型用均值或中位数,类别型用众数。如果活性值缺失,我建议用相似化合物的活性做KNN插补
  • 重度缺失(>20%):直接放弃这个特征。强行插补只会引入噪声,得不偿失
个人经验:对于描述符矩阵的缺失值,我更喜欢用迭代插补(IterativeImputer)。它考虑到了特征之间的关联性,效果比简单均值好不少。

异常值检测——揪出那个捣蛋鬼

异常值会让模型学偏。你想想看,一个离群点就能把线性回归的线拉歪,多可怕。我常用两种方法:

  1. Z-score法:计算每个值偏离均值的标准差数,>3的视为异常
  2. 箱线图法(IQR):Q1-1.5*IQR到Q3+1.5*IQR之外的算异常

实际项目中,我一般两种方法都跑,取交集。这样能减少误删正常数据的风险。

重要提醒:对于活性值(pIC50、pKi等)的异常值,不要轻易删除。先查原始文献,确认是不是实验误差。有时异常值反而是重要发现的前兆。

数据标准化——把不同尺度的数据拉到同一水平线

标准化有什么用?说白了,就是让描述符之间可以公平比较。一个描述符取值范围0-1,另一个0-1000,如果不标准化,模型会天然偏向数值大的那个。

方法公式适用场景
Z-score标准化(x-μ)/σ数据近似正态分布,大部分情况适用
Min-Max归一化(x-min)/(max-min)数据有明确边界,如[0,1]区间要求
Robust标准化(x-median)/IQR数据含有较多异常值

我个人发展,做QSAR时Z-score用得最多。但要注意——先划分训练集和测试集,再用训练集的均值和标准差去标准化测试集。千万别放一起标准化,否则会造成数据泄露。

from sklearn.preprocessing import StandardScaler

# 正确做法:分开拟合
X_train, X_test = train_test_split(X, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)  # 用训练集的参数
血的教训:我曾经把整个数据集一起标准化,然后做PCA。结果模型在验证集上效果贼好,心里美滋滋。后来做了个外部测试,结果直接崩了。查了半天才发现是数据泄露的问题。从那以后,我每次做预处理都极其注意训练/测试集的分离。

质量控制指标——给数据打分

数据预处理完了,怎么判断质量好不好?不能光凭感觉。我建议用几个量化指标来评估:

  • 数据覆盖率:有效描述符占总描述符的比例。低于70%要警惕
  • 特征稳定性:多次实验测量值的变异系数(CV)。CV>0.3说明这个特征不稳定
  • 样本代表性:训练集的化学空间能否覆盖测试集。用Tanimoto距离衡量
  • 活性分布:看活性值是否均匀分布。太偏的分布会影响模型泛化能力
小技巧:做一个数据质量报告表,每次预处理完都自动生成。包括缺失率、异常值数、特征稳定性等。这样方便追踪数据版本之间的质量变化。

下面是我整个数据预处理与质量控制的流程图,把每个步骤串起来看更清楚:

数据预处理与质量控制流程 原始数据 数据清洗 缺失值处理 异常值检测 数据标准化 质量控制评估 合格数据 → 建模 质量不达标 返回清洗步骤

这个流程看起来简单,但每一步都可能踩坑。我记得有个项目,数据清洗完觉得没问题了,结果建模后R²只有0.3。后来发现是异常值处理太保守,把一些变异大的但合法的结构给删了。从那以后,我每次处理异常值都会可视化看一下分布,再决定阈值。

总结一下关键点:
1. 数据清洗是基础,SMILES合法性检查必须做
2. 缺失值处理根据比例选择策略,别一刀切
3. 异常值检测结合Z-score和IQR,交叉验证
4. 标准化务必训练集和测试集分开
5. 质量控制要量化,用指标说话

数据预处理做得好,建模就成功了一半。嗯,这个环节花再多时间都值得。毕竟我们做QSAR的,最后拼的就是数据质量。数据干净了,模型自然就能学到真正有意义的规律。