You need to enable JavaScript to run this app. 使用Pandas的KNNImputer补全缺失数据时如何选取合适的K值
优惠活动
大模型
产品
解决方案
定价
更多

使用Pandas的KNNImputer补全缺失数据时如何选取合适的K值

KNNImputer的K值选取方案

现有代码误差一致的原因

  • 验证样本量太小:仅随机删除10个单元格,统计意义极弱,不同K值的效果差异会被随机误差完全覆盖,自然呈现误差一致的结果
  • 误差计算逻辑错误:sum(abs(compare_df-transformed_df))默认按列求和,返回的是每列的误差总和而非10个缺失点的总误差,结果没有参考性
  • 未固定随机种子:每次循环随机删除的位置不同,不同K值的验证集不统一,结果不具备可比性
  • 验证逻辑有偏差:用KNN填充后的结果作为真值,相当于用模型输出验证模型本身,会引入额外偏差
  • 未做特征标准化:KNN基于距离计算近邻,不同量纲的特征会导致距离计算完全失效,进一步抹平不同K值的效果差异

推荐的K值选取方法

方法1:带掩码的交叉验证(无后续建模任务时使用)

核心逻辑是从原始数据中随机选择原本非空的单元格作为验证集,手动将其设为缺失值,用填充值和真实值的误差作为评估指标,所有K值在同一个验证集上测试保证可比性。
示例代码如下:

import numpy as np
import pandas as pd
from sklearn.impute import KNNImputer
from sklearn.preprocessing import StandardScaler

# 第一步:标准化特征(必须做,否则KNN效果完全不准)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(ma_water_numeric)

# 第二步:构造统一的验证掩码
original_mask = ~np.isnan(X_scaled) # 原始数据中所有非空位置的掩码
total_valid = np.sum(original_mask)
n_validation = int(total_valid * 0.03) # 取3%的非空值作为验证集,可自行调整
# 固定随机种子保证可复现
rng = np.random.default_rng(seed=42)
# 随机选择验证位置
valid_flat_idx = rng.choice(np.where(original_mask.flatten())[0], size=n_validation, replace=False)
valid_rows, valid_cols = np.unravel_index(valid_flat_idx, X_scaled.shape)

# 第三步:构造带模拟缺失的数据集
X_masked = X_scaled.copy()
X_masked[valid_rows, valid_cols] = np.nan

# 第四步:遍历候选K值计算误差
candidate_k = [3,5,7,9,11,15,21,30]
error_list = []
for k in candidate_k:
    imputer = KNNImputer(n_neighbors=k)
    X_filled = imputer.fit_transform(X_masked)
    # 仅计算验证位置的平均绝对误差
    mae = np.mean(np.abs(X_filled[valid_rows, valid_cols] - X_scaled[valid_rows, valid_cols]))
    error_list.append((k, mae))

# 选取误差最小的K
best_k = sorted(error_list, key=lambda x:x[1])[0][0]

如果需要还原回原始量纲,只需要对填充后的数据集调用scaler.inverse_transform()即可。

方法2:绑定下游任务的网格搜索(有后续建模任务时使用)

如果填充数据是为了后续的分类、回归等建模任务,可以将KNNImputer和下游模型绑定为Pipeline,用交叉验证同时搜索K值和模型参数,选出来的K最适配最终业务目标。
示例代码如下:

from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('imputer', KNNImputer()),
    ('model', RandomForestRegressor(random_state=42))
])

param_grid = {
    'imputer__n_neighbors': [3,5,7,9,11,15],
    'model__n_estimators': [100,200]
}

# 5折交叉验证搜索最优参数,评估指标可根据任务替换
grid = GridSearchCV(pipe, param_grid, cv=5, scoring='neg_mean_absolute_error', n_jobs=-1)
grid.fit(X, y) # X为原始特征矩阵,y为下游任务的目标变量
print("最优K值:", grid.best_params_['imputer__n_neighbors'])

内容的提问来源于stack exchange,提问作者SamOfSchrodinger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 16:36:04