4. 缺失值处理(下):均值/中位数/众数填充、KNN填充、回归填充、多重插补法

在上一节中,我们讨论了缺失值的基本处理策略,包括删除法和简单统计量填充。本节将深入探讨更高级的填充技术,这些方法能够更好地保留数据分布特征,减少因填充引入的偏差。我们将从最简单的单变量填充逐步过渡到复杂的多变量插补方法。

4.1 单变量统计量填充:均值、中位数与众数

这是最基础且应用最广泛的填充方法,其核心思想是用该特征自身的集中趋势度量来替代缺失值。选择哪种统计量取决于数据的分布类型和业务含义。

统计量 适用场景 数学定义 优缺点
均值 (Mean) 数值型特征,数据近似正态分布,无极端异常值 \(\bar{x} = \frac{1}{n}\sum_{i=1}^{n}x_i\) 计算简单,但会降低方差,受异常值影响大
中位数 (Median) 数值型特征,数据偏态分布或存在明显异常值 排序后位于中间位置的值 对异常值鲁棒,能较好保持数据排序信息
众数 (Mode) 分类型特征(有序/无序),或离散数值型 出现频率最高的值 适用于类别数据,但可能引入模式偏差
实践建议: 在金融风控或医疗诊断场景中,特征往往呈现长尾分布(如收入、住院天数),此时应优先使用中位数填充。对于性别、地区等类别特征,则使用众数填充。均值填充仅适用于经过异常值清洗后的正态分布特征。

4.2 KNN 填充:基于近邻的相似性插补

KNN 填充利用样本间的相似性来估计缺失值。对于包含缺失值的样本,算法在数据集中找到与其最相似的 K 个完整样本(近邻),然后根据这些近邻对应特征的值进行加权或简单平均来填充缺失项。

核心参数: K 值(近邻数量)通常设为 3-10,距离度量常用欧氏距离或曼哈顿距离。特征需要先进行标准化/归一化处理,否则量纲大的特征会主导距离计算。
# Python 示例:使用 sklearn 的 KNNImputer
from sklearn.impute import KNNImputer
import numpy as np

# 模拟数据:包含缺失值
X = np.array([[1, 2, np.nan],
              [3, 4, 3],
              [7, 6, 5],
              [np.nan, 8, 7]])

# 初始化 KNN 填充器,K=2,使用距离加权平均
imputer = KNNImputer(n_neighbors=2, weights="distance")

# 执行填充
X_imputed = imputer.fit_transform(X)
print(X_imputed)
# 输出示例:
# [[1.  2.  4. ]
#  [3.  4.  3. ]
#  [7.  6.  5. ]
#  [5.  8.  7. ]]
注意事项: KNN 填充的计算复杂度为 O(n²),当数据集超过 10 万行时,计算时间会显著增加。此外,如果特征空间中存在大量噪声或无关特征,近邻的相似性度量会失真,导致填充效果下降。

4.3 回归填充:利用特征间线性关系

回归填充假设缺失特征与其他特征之间存在线性或非线性关系。它将缺失特征作为目标变量,其他完整特征作为自变量,建立回归模型来预测缺失值。

回归填充流程示意图 原始数据(含缺失) 步骤1:划分数据集 步骤2:训练回归模型 步骤3:预测缺失值 填充完成的数据集 说明:回归填充利用特征间的相关性,比单变量填充更准确,但可能强化数据中的线性假设
# Python 示例:使用线性回归进行填充
from sklearn.linear_model import LinearRegression
import pandas as pd
import numpy as np

# 假设 df 是包含缺失值的 DataFrame,'feature_A' 有缺失
# 使用其他完整特征预测 'feature_A'
train_df = df[df['feature_A'].notna()]
test_df = df[df['feature_A'].isna()]

X_train = train_df[['feature_B', 'feature_C', 'feature_D']]
y_train = train_df['feature_A']
X_test = test_df[['feature_B', 'feature_C', 'feature_D']]

model = LinearRegression()
model.fit(X_train, y_train)
predicted_values = model.predict(X_test)

# 填充缺失值
df.loc[df['feature_A'].isna(), 'feature_A'] = predicted_values

4.4 多重插补法 (MICE)

多重插补法(Multiple Imputation by Chained Equations, MICE)是目前统计学界公认最稳健的缺失值处理方法之一。它通过迭代的方式,为每个缺失值生成多个合理的填充值,从而反映填充的不确定性。

MICE 的核心步骤:

  1. 初始化: 先用均值/中位数等简单方法填充所有缺失值。
  2. 迭代循环: 对每个含有缺失值的特征,将其设为缺失状态,使用其他特征(包括已填充的值)建立回归模型,预测并更新该特征的缺失值。
  3. 重复: 步骤 2 经过多轮迭代(通常 5-10 轮),直到模型收敛。
  4. 生成多个数据集: 重复整个流程 M 次(通常 M=5),生成 M 个不同的完整数据集。
  5. 合并结果: 对 M 个数据集的分析结果进行 Rubin 规则合并,得到最终的参数估计和标准误。
方法 保留数据分布 考虑不确定性 计算开销 适用数据量
均值/中位数填充 低(压缩方差) 否 极低 任意规模
KNN 填充 中 否 高(O(n²)) 中小规模
回归填充 中高 否 中 中大规模
多重插补 (MICE) 高 是 高 中大规模
为什么多重插补优于单次填充? 单次填充(如均值、回归)将缺失值视为已知的确定值,这会低估标准误,导致假阳性率升高。多重插补通过生成多个填充版本,将填充的不确定性纳入统计推断,使得置信区间更宽、更真实。
# Python 示例:使用 miceforest 库进行多重插补
# 安装:pip install miceforest
import miceforest as mf
import pandas as pd

# 加载数据(假设 df 包含缺失值)
# df = pd.read_csv('your_data.csv')

# 创建内核并执行多重插补
kernel = mf.MultipleImputedKernel(
    data=df,
    datasets=5,          # 生成 5 个完整数据集
    save_all_iterations=True,
    random_state=2023
)

# 运行 MICE 算法(默认迭代 5 轮)
kernel.mice(iterations=5)

# 获取第 1 个完整数据集
completed_data_1 = kernel.complete_data(dataset=1)

# 对多个数据集进行分析并合并结果
# 例如:对每个数据集训练模型,然后合并参数估计

4.5 方法选择决策指南

在实际项目中,选择哪种填充方法需要综合考虑数据特征、缺失机制和计算资源。以下决策树可以帮助你快速做出选择:

缺失值填充方法选择决策树 缺失值比例 < 5%? 是 → 均值/中位数填充 否 → 考虑高级方法 数据量 < 5万? 数据量 ≥ 5万? KNN 或回归填充 多重插补 (MICE)
关键提醒: 无论选择哪种填充方法,都必须在填充前进行缺失机制分析。如果数据是随机缺失(MAR)或完全随机缺失(MCAR),上述方法均适用;但如果数据是非随机缺失(MNAR),即缺失本身与未观测到的值相关,则任何填充方法都可能引入偏差,此时应考虑使用选择模型或模式混合模型等更专业的处理方法。