You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sklearn KNN Imputer填充后仍有缺失值,原因何在?

KNNImputer填充后仍存在NaN的原因分析

问题背景

尝试用Sklearn的KNNImputer填充instrumentalness列的NaN值,填充前该列有3452个NaN,填充后仍剩余472个NaN。以下是数据清洗及填充的代码和结果:

数据清洗代码及输出

# Create row for both the singer and track name
train.insert(2,'Artist Track',(train['Artist Name']+ " " + train['Track Name']))

# Remove duplicates for same Artist, Song, and Class
# Sort values by Artist Track then columns with NaNs to possibly drop duplicates with NaNs
train.sort_values(by=['Artist Track','Popularity','key','instrumentalness'], inplace=True)
train.drop_duplicates(subset=['Artist Track', 'Class'], keep='first', inplace=True)

# Remove duplicates of tracks if instrumentalness duplicate is NaN
train.sort_values(by=['Artist Track','instrumentalness'], inplace=True)
dups_ins = train[train.duplicated(subset=['Artist Track'], keep='first')==True].index
ins_nans = np.where(train['instrumentalness'].isna())[0]
drop_ins = set(dups_ins).intersection(ins_nans)
train.drop(drop_ins, inplace=True)

# Remove duplicates of tracks if key duplicate is NaN
train.sort_values(by=['Artist Track','key'], inplace=True)
dups_key = train[train.duplicated(subset=['Artist Track'], keep='first')==True].index
key_nans = np.where(train['key'].isna())[0]
drop_key = set(dups_key).intersection(key_nans)
train.drop(drop_key, inplace=True)


# Remove duplicates of tracks if popularity duplicate is NaN
train.sort_values(by=['Artist Track','Popularity'], inplace=True)
dups_pop = train[train.duplicated(subset=['Artist Track'], keep='first')==True].index
pop_nans = np.where(train['Popularity'].isna())[0]
drop_pop = set(dups_pop).intersection(pop_nans)
train.drop(drop_pop, inplace=True)

train['instrumentalness'].isna().sum()

输出:

3452

KNN填充代码及输出

from sklearn.impute import KNNImputer 
fea_transformer = KNNImputer(n_neighbors=3)
values = fea_transformer.fit_transform(train[['instrumentalness']])
train['instrumentalness'] = pd.DataFrame(values)
train['instrumentalness'].isna().sum()

输出:

472

可能的原因

  • 仅用单一列做KNN填充,无法处理该列全NaN的样本组
    KNNImputer依赖特征相似度匹配邻近样本,用邻居均值填充NaN。但你只传入了instrumentalness这一列,如果某个样本该列是NaN,且所有其他样本该列也都是NaN(比如某歌手某首歌的所有样本该列全空),KNN找不到任何有有效值的邻居,只能保留NaN。
  • 孤立NaN样本的邻居无有效值
    你设置了n_neighbors=3,如果某个NaN样本的3个最近邻居(仅按instrumentalness列值计算)也都是NaN,就无法计算填充值,该样本的NaN会被保留。比如数据中存在连续的NaN块,块内样本找不到足够的有值邻居。
  • 数据清洗未覆盖全NaN的样本组
    你的清洗步骤仅删除重复的NaN样本,但对于单个Artist Track下仅存的唯一样本且该样本instrumentalness为NaN的情况,清洗后依然保留,这类样本在单一列填充时无法被KNN处理。

解决建议

  • 使用多特征列做KNN填充:加入和instrumentalness相关的特征(比如Popularity、key),让KNN能基于多维度相似度找邻居,示例代码:
    from sklearn.impute import KNNImputer 
    fea_transformer = KNNImputer(n_neighbors=3)
    # 传入多个相关特征列
    filled_values = fea_transformer.fit_transform(train[['instrumentalness', 'Popularity', 'key']])
    # 将填充后的instrumentalness列放回原数据集
    train['instrumentalness'] = filled_values[:, 0]
    
  • 检查剩余NaN样本:查看这472个样本的其他特征是否也全为空,或者是否属于同一类全NaN的组,这类样本可以单独用全局均值/中位数填充,或者直接删除。
  • 调整KNN参数:尝试减小n_neighbors(比如设为1),让样本更容易找到至少一个有值的邻居,但注意避免过拟合问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:10:50