如何获取5折交叉验证中经KNNImputer填充后的数据集?
问题:获取KNNImputer结合5折交叉验证后的填充数据集
你现在的情况是手里有个165条样本、49个特征的二分类数据集,存在缺失值,原本用KNNImputer配合5折交叉验证做填充,但不需要模型的准确率,而是要拿到每折填充后的数据集,用来做后续的特征选择和分类任务对吧?
cross_val_score这个工具确实只返回评估指标,不会给你填充后的数据。要拿到每折的填充结果,你需要手动遍历交叉验证的每一轮拆分,自己完成Imputer的拟合和数据转换,这样既能保持交叉验证中“训练集拟合、测试集转换”的无偏逻辑,又能拿到你需要的填充后数据。
下面是具体的实现代码:
import numpy as np import pandas as pd from sklearn.impute import KNNImputer from sklearn.model_selection import RepeatedStratifiedKFold # 1. 加载并预处理数据 df = pd.read_csv('data.csv', header=None, na_values='?') data = df.values # 分离特征和标签(标签在第49列,索引从0开始) ix = [i for i in range(data.shape[1]) if i != 49] X, y = data[:, ix], data[:, 49] # 2. 设置交叉验证拆分器(和你之前用的一致) cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=1, random_state=1) # 3. 遍历每折,完成填充并保存结果 fold_filled_data = [] for fold_num, (train_idx, test_idx) in enumerate(cv.split(X, y), start=1): # 拆分当前折的训练和测试数据 X_train, X_test = X[train_idx], X[test_idx] y_train, y_test = y[train_idx], y[test_idx] # 仅在训练集上拟合Imputer(避免数据泄露) imputer = KNNImputer(n_neighbors=5, weights='uniform', metric='nan_euclidean') imputer.fit(X_train) # 用拟合好的Imputer填充训练集和测试集 X_train_filled = imputer.transform(X_train) X_test_filled = imputer.transform(X_test) # 把填充后的特征和标签合并成完整数据集 train_full = pd.DataFrame(np.hstack((X_train_filled, y_train.reshape(-1, 1)))) test_full = pd.DataFrame(np.hstack((X_test_filled, y_test.reshape(-1, 1)))) full_fold = pd.concat([train_full, test_full], axis=0) # 存储当前折的数据,或者直接保存到文件 fold_filled_data.append((f"第{fold_num}折", full_fold)) full_fold.to_csv(f"filled_data_fold_{fold_num}.csv", index=False, header=False) # 之后你就可以从fold_filled_data里取出每折的数据,进行特征选择了
额外说明
- 这里严格遵循了交叉验证的原则:只在训练数据上拟合Imputer,再用它填充测试数据,避免了数据泄露(如果直接用全量数据拟合Imputer再填充,会导致测试集的信息提前泄露给模型,影响后续任务的可靠性)。
- 如果你后续的流程是“填充→特征选择→分类”,其实更推荐把特征选择也加入到Pipeline中,让整个流程在交叉验证里自动运行,这样能彻底避免数据泄露。比如:
from sklearn.feature_selection import SelectKBest, f_classif from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import Pipeline from sklearn.model_selection import cross_val_score # 定义完整流程的Pipeline pipeline = Pipeline(steps=[ ('imputer', KNNImputer(n_neighbors=5)), ('feature_selection', SelectKBest(f_classif, k=20)), # 选择top20特征 ('classifier', RandomForestClassifier()) ]) # 评估整个流程的准确率 scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
但如果确实需要单独拿到填充后的数据来做特征选择,前面的手动循环方法就完全适用。
内容的提问来源于stack exchange,提问作者a_m
相关产品推荐
相关产品推荐

