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

拟合数据时如何避免NaN错误?K-NN分类器解决方案咨询

问题描述

以下是用于明日降雨预测(是/否二元分类)的代码:

#Load weather data
data = pd.read_csv(r"C:\Users\slick\Downloads\weather_dataset.csv")

#Hot encode data, for columns with information that is not 
df_weather_processed = pd.get_dummies(data, columns=['Location','RainToday', 'WindGustDir', 'Cloud9am', 'Cloud3pm','WindDir9am', 'WindDir3pm'])

df_weather_processed.replace(['No', 'Yes'], [0,1], inplace=True
)

df_weather_processed.drop('Date',axis=1,inplace=True)
df_weather_processed = df_weather_processed.astype(float)
features = df_weather_processed.drop(columns='RainTomorrow', axis=1)
Y = df_weather_processed['RainTomorrow']

df_weather_processed.fillna(0)

#Split data into training and test sets
x_train, x_test, y_train, y_test = train_test_split( features,Y, test_size=0.2, random_state=10)

#Create instance of and train model
for i in range(1,20,2):
    k = KNeighborsClassifier(n_neighbors=i)
    k.fit(x_train, y_train.values.ravel())
    
    #Make predictions
    pred = k.predict(X_test)

    print("KNN ", i, ":")
    
    #Accuracy
    print("\tAccuracy: ", k.score(X_test, y_test))
    
    tn, fp, fn, tp = confusion_matrix(y_test, pred).ravel()

    #Precision
    precision = tp/(tp+fp)
    print("\tPrecision: ", precision)

    #Recall
    recall = tp/(tp+fn)
    print("\tRecall: ", recall)
    
    #F1 score
    F1 = 2 * (precision * recall) / (precision + recall)
    print("\tF1 score: ", F1)
    
    #AUC
    fpr, tpr, thresholds = metrics.roc_curve(y_test, pred)
    roc_auc = metrics.auc(fpr, tpr)
    print("\tAUC score: ", roc_auc, "\n")

运行时触发ValueError:Input X contains NaN. KNeighborsClassifier does not accept missing values encoded as NaN natively。尝试添加df_weather_processed.fillna(0)后问题未解决,后续又出现Input Y contains NaN的错误,且该问题在DecisionTrees、SVM模型中同样存在。

问题成因分析
  1. 缺失值处理无效:df_weather_processed.fillna(0)既没有原地修改数据,也没有将结果赋值给变量,导致后续拆分的features和Y仍保留原始缺失值;且处理步骤在拆分特征和标签之后,完全起不到作用。
  2. NA值假设不合理:并非所有缺失值都代表0,比如温度、风速等连续型特征的缺失值,直接填充0会引入数据偏差,影响模型效果。
  3. 目标变量未处理缺失值:RainTomorrow列存在缺失值,之前的代码未对其进行处理,导致后续模型拟合时出现Input Y contains NaN的错误。
  4. 变量名不一致:代码中使用X_test(大写X),但拆分数据时定义的是x_test(小写x),这也会导致运行错误。
基于K-NN分类器的解决方案

以下是修正后的完整代码,解决了缺失值处理、变量名等问题:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, roc_curve, auc

# 加载天气数据
data = pd.read_csv(r"C:\Users\slick\Downloads\weather_dataset.csv")

# 1. 先处理目标变量的缺失值:删除RainTomorrow为NaN的行
data = data.dropna(subset=['RainTomorrow'])

# 2. 分类变量独热编码
df_weather_processed = pd.get_dummies(data, columns=['Location','RainToday', 'WindGustDir', 'Cloud9am', 'Cloud3pm','WindDir9am', 'WindDir3pm'])

# 3. 将Yes/No转换为1/0
df_weather_processed.replace(['No', 'Yes'], [0,1], inplace=True)

# 4. 删除无用列
df_weather_processed.drop('Date',axis=1,inplace=True)

# 5. 处理特征的缺失值:连续型特征用中位数填充,避免0值偏差
continuous_cols = ['MinTemp', 'MaxTemp', 'Rainfall', 'Evaporation', 'Sunshine', 
                   'WindGustSpeed', 'WindSpeed9am', 'WindSpeed3pm', 'Humidity9am', 
                   'Humidity3pm', 'Pressure9am', 'Pressure3pm', 'Temp9am', 'Temp3pm']
for col in continuous_cols:
    df_weather_processed[col] = df_weather_processed[col].fillna(df_weather_processed[col].median())

# 6. 转换数据类型
df_weather_processed = df_weather_processed.astype(float)

# 7. 拆分特征和标签
features = df_weather_processed.drop(columns='RainTomorrow', axis=1)
Y = df_weather_processed['RainTomorrow']

# 8. 拆分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(features, Y, test_size=0.2, random_state=10)

# 9. 训练并评估K-NN模型
for i in range(1,20,2):
    k = KNeighborsClassifier(n_neighbors=i)
    k.fit(x_train, y_train.values.ravel())
    
    # 预测(修正变量名:x_test而非X_test)
    pred = k.predict(x_test)

    print(f"KNN {i}:")
    
    # 准确率
    print(f"\tAccuracy: {k.score(x_test, y_test):.4f}")
    
    tn, fp, fn, tp = confusion_matrix(y_test, pred).ravel()

    # 精确率
    precision = tp/(tp+fp) if (tp+fp) !=0 else 0
    print(f"\tPrecision: {precision:.4f}")

    # 召回率
    recall = tp/(tp+fn) if (tp+fn) !=0 else 0
    print(f"\tRecall: {recall:.4f}")
    
    # F1分数
    F1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) !=0 else 0
    print(f"\tF1 score: {F1:.4f}")
    
    # AUC分数
    fpr, tpr, thresholds = roc_curve(y_test, pred)
    roc_auc = auc(fpr, tpr)
    print(f"\tAUC score: {roc_auc:.4f}\n")
未来避免此类问题的建议
  • 按顺序执行预处理步骤:遵循「加载数据→检查缺失值→处理缺失值→特征编码→拆分数据集」的流程,确保所有数据清洗操作在拆分前完成,避免训练集和测试集处理不一致。
  • 验证缺失值处理效果:执行填充/删除操作后,用df.isna().sum()检查各列缺失值数量,确认处理生效。
  • 合理选择缺失值填充策略:连续型特征优先用中位数/均值填充,分类特征用众数填充,不要随意假设缺失值为0。
  • 检查变量名一致性:确保代码中变量名大小写、拼写完全一致,避免因笔误导致的错误。
  • 处理目标变量缺失值:分类任务中,目标变量的缺失值建议直接删除对应行,或根据业务逻辑填充,不要忽略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:50:59