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

使用KNN填充DataFrame缺失值时触发ValueError问题求助

问题:使用KNN算法填充DataFrame缺失值时触发ValueError

我在使用KNN算法填充DataFrame缺失值时遇到了问题。以下是df.info()的输出结果:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1162 entries, 0 to 1161
Data columns (total 61 columns):
 #   Column                                        Non-Null Count  Dtype  
---  ------                                        --------------  -----  
 0   Algorithms&DataStructures                     428 non-null    float64
 1   C/C++Programming                              688 non-null    float64
 2   Calculus1                                     835 non-null    float64
 3   Calculus2                                     752 non-null    float64
 4   Calculus3                                     366 non-null    float64
 5   ChemistryLaboratory                           497 non-null    float64
 6   ChemistryforEngineers                         823 non-null    float64
 7   ComputerArchitecture                          433 non-null    float64

我使用的NaN填充函数来自Kaggle的《Bayesian Regression | House Price Prediction》notebook,代码如下:

from sklearn.neighbors import KNeighborsRegressor
import numpy as np
import pandas as pd

# function that imputes a dataframe 
def impute_knn(df):
    
    ''' inputs: pandas df containing feature matrix '''
    ''' outputs: dataframe with NaN imputed '''
    # imputation with KNN unsupervised method
    # separate dataframe into numerical/categorical
    ldf = df.select_dtypes(include=[np.number])           # select numerical columns in df
    ldf_putaside = df.select_dtypes(exclude=[np.number])  # select categorical columns in df
    # define columns w/ and w/o missing data
    cols_nan = ldf.columns[ldf.isna().any()].tolist()         # columns w/ nan 
    cols_no_nan = ldf.columns.difference(cols_nan).values     # columns w/o nan 

    for col in cols_nan:                
        imp_test = ldf[ldf[col].isna()]   # indicies which have missing data will become our test set
        imp_train = ldf.dropna()          # all indicies which which have no missing data 
        model = KNeighborsRegressor(n_neighbors=5)  # KNR Unsupervised Approach
        knr = model.fit(imp_train[cols_no_nan], imp_train[col])
        ldf.loc[df[col].isna(), col] = knr.predict(imp_test[cols_no_nan])
    
    return pd.concat([ldf,ldf_putaside],axis=1)

调用该函数时触发了以下错误:

ValueError                                Traceback (most recent call last)
<ipython-input-284-b13fac408835> in <module>
----> 1 df2 = impute_knn(df)
      2 # looks like we have a full feature matrix
      3 df2.info()

5 frames
/usr/local/lib/python3.8/dist-packages/sklearn/utils/validation.py in check_array(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator)
    663 
    664         if all(isinstance(dtype, np.dtype) for dtype in dtypes_orig):
--> 665             dtype_orig = np.result_type(*dtypes_orig)
    666 
    667     if dtype_numeric:

<__array_function__ internals> in result_type(*args, **kwargs)

ValueError: at least one array or dtype is required

分析与解决方法

错误核心原因

这个报错的本质是cols_no_nan为空数组——也就是所有数值列都存在缺失值。原函数逻辑中,训练KNN模型时依赖完全无缺失的列作为特征,但当所有列都有缺失时,imp_train[cols_no_nan]会返回空DataFrame,而KNeighborsRegressor.fit()无法处理空的特征矩阵,进而触发np.result_type的参数错误。

从你提供的df.info()结果能看到,列出的8个数值列非空计数均小于总行数1162,说明所有数值列都存在缺失值,直接导致cols_no_nan没有任何元素。

修复方案

方案1:调整KNN填充逻辑,适配全列有缺失的场景

修改函数逻辑,对每个要填充的列,使用除当前列外的所有数值列作为特征,同时过滤掉特征列存在缺失的行来构建训练集和测试集:

from sklearn.neighbors import KNeighborsRegressor
import numpy as np
import pandas as pd

def impute_knn(df):
    ldf = df.select_dtypes(include=[np.number])
    ldf_putaside = df.select_dtypes(exclude=[np.number])
    cols_nan = ldf.columns[ldf.isna().any()].tolist()

    for col in cols_nan:
        # 取当前列之外的所有数值列作为特征
        feature_cols = [c for c in ldf.columns if c != col]
        # 训练集:当前列和特征列均无缺失的行
        imp_train = ldf.dropna(subset=[col] + feature_cols)
        # 测试集:当前列缺失但特征列无缺失的行
        imp_test = ldf[ldf[col].isna()].dropna(subset=feature_cols)
        
        # 处理训练集或测试集为空的情况,用均值填充剩余缺失值
        if len(imp_train) == 0 or len(imp_test) == 0:
            ldf.loc[ldf[col].isna(), col] = ldf[col].mean()
            continue
            
        model = KNeighborsRegressor(n_neighbors=5)
        knr = model.fit(imp_train[feature_cols], imp_train[col])
        ldf.loc[imp_test.index, col] = knr.predict(imp_test[feature_cols])
        
        # 处理测试集中特征列也有缺失的行,用均值填充
        remaining_nan = ldf[col].isna() & ldf[feature_cols].isna().any(axis=1)
        ldf.loc[remaining_nan, col] = ldf[col].mean()
    
    return pd.concat([ldf, ldf_putaside], axis=1)

方案2:先简单填充部分列,再用原逻辑运行KNN

如果想保留原函数逻辑,可以先对缺失率较低的列用均值/中位数填充,制造出完全无缺失的特征列后再运行原函数:

# 先填充缺失率低于20%的列
low_missing_cols = ldf.columns[ldf.isna().mean() < 0.2]
ldf[low_missing_cols] = ldf[low_missing_cols].fillna(ldf[low_missing_cols].mean())

# 再运行原impute_knn函数
df_filled = impute_knn(ldf)

额外注意事项

  • 运行KNN填充前,建议对数值列做标准化/归一化,因为KNN基于距离计算,不同尺度的特征会严重影响填充结果。
  • 如果某列缺失率超过50%,建议考虑删除该列,或者使用MICE等更适合高缺失率场景的填充方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 02:35:19