拟合数据时如何避免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模型中同样存在。
问题成因分析
- 缺失值处理无效:
df_weather_processed.fillna(0)既没有原地修改数据,也没有将结果赋值给变量,导致后续拆分的features和Y仍保留原始缺失值;且处理步骤在拆分特征和标签之后,完全起不到作用。 - NA值假设不合理:并非所有缺失值都代表0,比如温度、风速等连续型特征的缺失值,直接填充0会引入数据偏差,影响模型效果。
- 目标变量未处理缺失值:
RainTomorrow列存在缺失值,之前的代码未对其进行处理,导致后续模型拟合时出现Input Y contains NaN的错误。 - 变量名不一致:代码中使用
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
相关产品推荐
相关产品推荐

