如何复现scikit-learn RFECV类cv_results_中的交叉验证分数?
对递归特征消除交叉验证(RFECV)的理解
sklearn.feature_selection.RFECV的核心逻辑:
- 传入带有
coef_或feature_importances_属性的算法,先在全特征数据集上训练,生成特征重要性排名 - 通过交叉验证评估当前特征集下的模型性能
- 移除排名最低的特征,重新训练模型生成新的重要性排名,再次交叉验证评估
- 重复上述过程,直到剩余特征数达到
min_features_to_select指定值(默认1个) - 最终选择交叉验证分数最高的特征数量
问题
我能从rfecv.cv_results_["mean_test_score"]获取不同特征数量对应的交叉验证分数,但手动复现n-1个特征对应的分数时,结果和内置方法不一致。
手动复现代码:
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import StratifiedKFold from sklearn.model_selection import cross_validate from sklearn.feature_selection import RFECV alg = DecisionTreeClassifier(random_state = 0) cv_split = StratifiedKFold(5) # train是pandas数据框,x_var和y_var均为包含变量名的列表 X = train[x_var] y = np.ravel(train[y_var]) alg.fit(X, y) lowest_ranked_feature = np.argmin(alg.feature_importances_) x_var.pop(lowest_ranked_feature) one_removed_feature = train[x_var] alg.fit(one_removed_feature, y) cv_score = cross_validate(alg, one_removed_feature, y, cv=cv_split, scoring="accuracy") np.mean(cv_score["test_score"])
内置方法获取分数的代码:
rfecv = RFECV( estimator=alg, step=1, cv=cv_split, scoring="accuracy", ) rfecv.fit(X, y) rfecv.cv_results_["mean_test_score"][-2]
注:全特征(n个)对应的分数,手动复现和内置方法结果一致。
解决方法
你手动复现的逻辑和RFECV的核心差异在于:RFECV是在每个交叉验证的训练子集内独立完成特征选择,而非用整个数据集的特征重要性决定移除哪个特征。
正确的手动复现步骤及代码:
- 遍历StratifiedKFold的每个训练/测试折
- 在每个训练折上训练模型,得到特征重要性并移除排名最低的特征
- 用筛选后的训练折特征重新训练模型,在对应测试折上评估分数
- 取所有测试折分数的平均值
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import StratifiedKFold import numpy as np alg = DecisionTreeClassifier(random_state=0) cv_split = StratifiedKFold(5) X = train[x_var] y = np.ravel(train[y_var]) scores = [] for train_idx, test_idx in cv_split.split(X, y): # 拆分当前折的训练和测试数据 X_train, X_test = X.iloc[train_idx], X.iloc[test_idx] y_train, y_test = y[train_idx], y[test_idx] # 在训练折上训练模型,确定要移除的特征 temp_alg = DecisionTreeClassifier(random_state=0) temp_alg.fit(X_train, y_train) lowest_rank_idx = np.argmin(temp_alg.feature_importances_) # 同步移除训练和测试折中的目标特征 X_train_selected = X_train.drop(X_train.columns[lowest_rank_idx], axis=1) X_test_selected = X_test.drop(X_test.columns[lowest_rank_idx], axis=1) # 用筛选后的特征训练模型并评估 temp_alg.fit(X_train_selected, y_train) scores.append(temp_alg.score(X_test_selected, y_test)) # 计算平均分数,与rfecv.cv_results_["mean_test_score"][-2]结果一致 np.mean(scores)
关键注意点:
- 必须在每个交叉验证的训练折内单独做特征选择,避免用全数据集的特征重要性导致数据泄露
- 每次循环重新初始化模型,避免之前的训练状态干扰结果
- 测试折要同步移除对应特征,保证与训练折的特征集一致
内容的提问来源于stack exchange,提问作者AvanishM
相关产品推荐
相关产品推荐

