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 回归填充:利用特征间线性关系
回归填充假设缺失特征与其他特征之间存在线性或非线性关系。它将缺失特征作为目标变量,其他完整特征作为自变量,建立回归模型来预测缺失值。
# 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 的核心步骤:
- 初始化: 先用均值/中位数等简单方法填充所有缺失值。
- 迭代循环: 对每个含有缺失值的特征,将其设为缺失状态,使用其他特征(包括已填充的值)建立回归模型,预测并更新该特征的缺失值。
- 重复: 步骤 2 经过多轮迭代(通常 5-10 轮),直到模型收敛。
- 生成多个数据集: 重复整个流程 M 次(通常 M=5),生成 M 个不同的完整数据集。
- 合并结果: 对 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 方法选择决策指南
在实际项目中,选择哪种填充方法需要综合考虑数据特征、缺失机制和计算资源。以下决策树可以帮助你快速做出选择:
关键提醒: 无论选择哪种填充方法,都必须在填充前进行缺失机制分析。如果数据是随机缺失(MAR)或完全随机缺失(MCAR),上述方法均适用;但如果数据是非随机缺失(MNAR),即缺失本身与未观测到的值相关,则任何填充方法都可能引入偏差,此时应考虑使用选择模型或模式混合模型等更专业的处理方法。