2. 数据预处理基础:缺失值与异常值处理

数据预处理是特征工程的基石。原始数据几乎总是包含缺失值、异常值或不一致记录,若不处理,后续建模会产生偏差甚至错误。本章聚焦于缺失值处理与异常值检测两大核心任务,提供从基础到进阶的完整方案。

2.1 缺失值处理

缺失值产生的原因多样:设备故障、用户未填写、数据合并错位等。处理策略分为三类:删除、填充与模型预测。

2.1.1 删除法

删除法是最简单的策略,但会损失样本量,适用于缺失比例极低或随机缺失的场景。

方法 操作 适用场景 风险
行删除 删除含缺失值的整行 缺失率 < 5%,且随机缺失 样本量减少,可能引入偏差
列删除 删除缺失率过高的整列 缺失率 > 70%,且信息量低 丢失潜在有用特征
成对删除 只在计算具体统计量时排除缺失 相关性分析、协方差计算 不同统计量基于不同样本,结果不一致
注意: 删除法在非随机缺失(MNAR)场景下会严重扭曲数据分布,务必先分析缺失机制。

2.1.2 统计量填充

用集中趋势统计量替换缺失值,简单高效,但会降低方差,削弱特征区分度。

  • 均值填充: 适用于近似正态分布的数值特征。
  • 中位数填充: 适用于偏态分布或存在异常值的数值特征,鲁棒性强。
  • 众数填充: 适用于分类特征或离散数值特征。
  • 常数填充: 用业务含义明确的特殊值(如 -1、0、'Unknown')填充,保留缺失信息。
import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({'age': [25, np.nan, 30, 35, np.nan, 28],
                   'income': [50000, 60000, np.nan, 55000, 65000, 58000],
                   'gender': ['M', 'F', 'F', np.nan, 'M', 'F']})

# 均值填充
df['age_filled_mean'] = df['age'].fillna(df['age'].mean())

# 中位数填充
df['income_filled_median'] = df['income'].fillna(df['income'].median())

# 众数填充
df['gender_filled_mode'] = df['gender'].fillna(df['gender'].mode()[0])

print(df[['age', 'age_filled_mean', 'income', 'income_filled_median', 'gender', 'gender_filled_mode']])

2.1.3 模型预测填充

将缺失特征作为目标变量,利用其他完整特征构建预测模型进行填充。精度高,但计算成本大,且可能引入模型偏差。

方法 模型类型 优点 缺点
KNN 填充 无监督 利用样本相似性,无需假设分布 对 K 值敏感,高维数据效果差
回归填充 有监督 利用特征间线性关系 假设线性关系,可能过拟合
随机森林填充 有监督 处理非线性关系,自带特征重要性 计算量大,需调参
MICE(链式方程) 迭代多模型 处理多变量缺失,理论成熟 实现复杂,迭代收敛慢
实践建议: 对于中小规模数据(< 10 万行),优先尝试 KNN 填充(K=5~10)或随机森林填充;对于大规模数据,使用中位数/众数填充更高效。
缺失值处理策略决策流程 原始数据含缺失值 缺失率 < 5% 且随机缺失? 是 行删除 否 统计量填充 模型预测填充(可选) 说明:先判断缺失机制与比例,再选择策略;模型预测填充通常作为最后优化步骤

2.2 异常值检测与处理

异常值(Outlier)是显著偏离其他观测值的样本点。异常值可能由测量误差、数据录入错误或真实稀有事件引起,需根据业务场景决定保留或修正。

2.2.1 3σ 原则(拉依达准则)

基于正态分布假设:数据落在均值 ±3 倍标准差之外的概率仅为 0.27%,视为异常。

  • 适用条件: 数据近似服从正态分布。
  • 计算公式: 异常值区间为 (μ - 3σ, μ + 3σ) 之外。
  • 局限性: 对偏态分布和多重异常值敏感,标准差本身会被异常值拉大。
import numpy as np

def detect_outliers_3sigma(data):
    mean = np.mean(data)
    std = np.std(data)
    lower_bound = mean - 3 * std
    upper_bound = mean + 3 * std
    outliers = [x for x in data if x < lower_bound or x > upper_bound]
    return outliers, lower_bound, upper_bound

# 示例
data = [10, 12, 11, 13, 100, 9, 11, 12, 10, 11]
outliers, lb, ub = detect_outliers_3sigma(data)
print(f"下界: {lb:.2f}, 上界: {ub:.2f}")
print(f"检测到异常值: {outliers}")

2.2.2 IQR(四分位距)法

基于分位数,不依赖分布假设,鲁棒性强,是实际项目中最常用的方法。

  • 定义: IQR = Q3 - Q1(第三四分位数与第一四分位数之差)。
  • 异常判定: 小于 Q1 - 1.5×IQR 或大于 Q3 + 1.5×IQR 的点。
  • 极端异常: 使用 3×IQR 作为倍数,判定为极端异常值。
倍数 区间 异常程度 常见处理
1.5 × IQR [Q1 - 1.5IQR, Q3 + 1.5IQR] 温和异常 截尾、替换或单独标记
3.0 × IQR [Q1 - 3.0IQR, Q3 + 3.0IQR] 极端异常 优先删除或深入调查

2.2.3 箱线图可视化

箱线图(Box Plot)是 IQR 法的图形化呈现,可直观展示数据分布、偏态和异常点。

箱线图关键元素:
  • 箱体: 上边界 Q3,下边界 Q1,箱内线为中位数。
  • 须(Whisker): 延伸至 1.5×IQR 范围内的最远非异常点。
  • 异常点: 须之外的点,通常用圆点或星号标记。
箱线图与 IQR 异常检测示意 最小值 Q1 中位数 Q3 最大值 异常点 异常点 IQR 法:异常点 = 小于 Q1 - 1.5×IQR 或大于 Q3 + 1.5×IQR 的观测值 箱体包含 50% 的数据,中位数将箱体分为上下两部分

2.2.4 异常值处理策略

检测到异常值后,需根据业务含义选择处理方式,不可机械删除。

策略 操作 适用场景
删除 直接移除异常样本 确认是录入错误或测量故障
截尾(Winsorize) 将异常值替换为边界值(如 Q1 或 Q3) 保留样本量,降低极端值影响
视为缺失 标记为 NaN,再用填充方法处理 不确定异常原因,保留处理弹性
单独编码 创建二值特征标记是否为异常 异常本身可能携带业务信息(如欺诈)
变换 对数变换、Box-Cox 变换压缩尺度 偏态分布,异常值来自自然长尾
实践建议: 在金融风控、医疗诊断等场景,异常值可能代表欺诈或疾病,应单独编码保留;在传感器数据处理中,异常值多为噪声,优先截尾或删除。

2.3 本章小结

  • 缺失值处理: 从删除到统计量填充再到模型预测,精度递增但成本也递增;务必先分析缺失机制。
  • 异常值检测: 3σ 原则适用于正态分布,IQR 法更通用;箱线图是直观的辅助工具。
  • 处理策略: 删除、截尾、标记、变换各有适用场景,需结合业务判断。
  • 工程要点: 所有预处理步骤应在训练集上拟合参数(均值、分位数等),再应用到测试集,避免数据泄露。