部分手动应用Pipeline和嵌套交叉验证,使用RFECV和GridSearch

我正在尝试以一种比在cross_val_score中使用GridSearchCV更加手动的方式实现嵌套交叉验证,这样我可以更好地控制我的操作,考虑数据泄漏,观察我的变量和超参数如何变化,并记录它们,同时也为了更清楚地理解一切是如何工作的。

我想问一下下面的实现看起来是否合理。

处理流程:数据泄漏

分类变量

cat_pipe = Pipeline([("encoder",OneHotEncoder(drop="first"))])

可能为分类的数值特征

num_pipe = Pipeline([("encoder",OneHotEncoder(drop="first"))])

连续变量

num_cont_pipe = Pipeline([("scaler",StandardScaler())])preprocessor = ColumnTransformer(transformers=[('cat', cat_pipe, cat_var),                                               ('num', num_pipe, num_cat_vars), "num_cont",num_cont_pipe,num_cont)],n_jobs=-1)#,sparse_threshold=0)

嵌套交叉验证

cv_outer = StratifiedKFold(n_splits=5, random_state=0)cv_inner = StratifiedKFold(n_splits=10,random_state=0) # RepeatedStratifiedKFold(n_repeats=3,n_splits=10,random_state=0)

估计器和模型

estimator = RandomForestClassifier(class_weight="balanced")model = XGBClassifier(eval_metric="logloss")

特征选择和超参数优化

rfe = RFECV(estimator,cv=cv_inner, scoring="roc_auc",n_jobs=-1)

实现

for train_ix, test_ix in cv_outer.split(X,y):    time_start_outer = time.time()    X_train = X.iloc[train_ix,:]    X_test = X.iloc[test_ix,:]    y_train = y.iloc[train_ix]    y_test = y.iloc[test_ix]    # 数据准备    X_train_enc = preprocessor.fit_transform(X_train)    X_test_enc = preprocessor.transform(X_test)            # 特征选择    X_train_enc_var = rfe.fit(X_train_enc,y_train)    print(f"The number of features selected is {X_train_enc_var.n_features_}", sep="/n")    X_train_enc_var = rfe.transform(X_train_enc)    X_test_enc_var = rfe.transform(X_test_enc)    # 超参数调优     counter = Counter(y_train)    weight = counter[0] / counter[1]    hyper_params = {        # XGBClassifier        "scale_pos_weight":[1,2,3,4,5,6,weight,7,8,9,10,11,12]        }    grid_search = GridSearchCV(model,cv=cv_inner,param_grid=hyper_params,n_jobs=-1,scoring="roc_auc")    X_train_enc_var_hyp = grid_search.fit(X_train_enc_var,y_train)    best_model = X_train_enc_var_hyp.best_estimator_    yhat = best_model.predict(X_test_enc_var)    # 评估模型    score = roc_auc_score(y_test, yhat)    # 存储结果    outer_results.append(score)    outer_params.append(X_train_enc_var_hyp.best_params_)    # 报告进度    print(f' test_score= {score}, validation_score= {X_train_enc_var_hyp.best_score_}')# 总结模型的估计性能print(f'best_score: {np.mean(outer_results)}, {np.std(outer_results)}')

回答:

我注意到了三件事。

首先,不重要:

    # 特征选择    X_train_enc_var = rfe.fit(X_train_enc,y_train)    print(f"The number of features selected is {X_train_enc_var.n_features_}", sep="/n")    X_train_enc_var = rfe.transform(X_train_enc)    X_test_enc_var = rfe.transform(X_test_enc)

您将拟合的rfe保存到X_train_enc_var中,然后在两行后将其覆盖为转换后的数据集。这一切都按您希望的方式进行,但为了更忠实于变量名称:

    X_train_enc_var = rfe.fit_transform(X_train_enc,y_train)    X_test_enc_var = rfe.transform(X_test_enc)    print(f"The number of features selected is {rfe.n_features_}", sep="/n")

其次,您对递归特征消除和网格搜索分别使用了相同的cv_inner。这意味着选定的特征数量包含了(内部)测试折叠的信息,因此网格搜索得分可能存在乐观偏见。这可能不是什么大问题,因为您只关心搜索的相对得分。但是,可能某些超参数组合在不同数量的特征下表现得更好,从而被惩罚了。

最后,最严重但也是最容易修复的问题:您调用best_model.predict(...),但由于您使用的是roc_auc_score,您应该改为使用best_model.predict_proba(...)[:, 1]来获取正类别的概率得分。

另一个建议:由于您进行了大量计算,请保存更多信息:例如rfe的grid_scores_和网格搜索的cv_results_

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注