我想对我的数据框进行网格搜索交叉验证。
在我的管道中,我使用了一个自定义转换器来格式化数据。然而,当我在自定义转换器中打印数据的形状时,它被打印了11次(转换器被调用了11次)。
我以为它应该被打印10次,因为它转换了训练和测试数据框,每个5次,因为这是交叉验证。所以5 x 2 = 10。
但是显示了第11个形状,实际上是完整数据框的维度(未分成训练/测试)。
你知道这个第11次调用的原因吗?
这里有一部分代码来理解这个问题:
def binary_data(df): df.gender = df.gender.map({'Female': 0, 'Male': 1}) print(df.shape) return dfpipeline = ColumnTransformer([('binarydata', FunctionTransformer(binary_data), ['gender'])])param_grid = {}search = GridSearchCV(pipeline, param_grid, scoring='accuracy')search.fit(X, y)
编辑:refit=True(默认)标志实际上是额外调用的原因
回答:
我构建了一个示例来检查这个行为
import pandas as pdfrom sklearn.model_selection import GridSearchCVfrom sklearn.compose import ColumnTransformerfrom sklearn.preprocessing import FunctionTransformerfrom sklearn.linear_model import LogisticRegressionfrom sklearn.pipeline import Pipelinevalues = [{'gender':'Female'} if i%2==0 else {'gender':'Male'} for i in range(100)]X = pd.DataFrame(values)y = [0 if i%2==0 else 1 for i in range(100)]def binary_data(df): df.gender = df.gender.map({'Female': 0, 'Male': 1}) print(df.shape) return dfcolumntransf = ColumnTransformer([('binarydata', FunctionTransformer(binary_data), ['gender'])])model_pipeline = Pipeline([ ('preprocessing', columntransf), ('classifier', LogisticRegression(solver='lbfgs'))])param_grid = {}search = GridSearchCV(model_pipeline, param_grid, scoring='accuracy')search.fit(X, y)
是的,正如你所说,我得到了11次打印:
(80, 1)(20, 1)(80, 1)(20, 1)(80, 1)(20, 1)(80, 1)(20, 1)(80, 1)(20, 1)(100, 1)
但是,你看到最后一个集合的大小了吗?它是整个数据集的大小。
你忘了机器学习模型的主要目标是什么。从数据集中学习。从你数据集中的所有数据中学习。
你用交叉验证试图做的是在用网格搜索寻找最佳超参数时,获取模型性能的估计
为了更清楚,cv 用于评估你的模型在你的参数集下的表现,然后,你的整个数据集,使用最佳参数,用于学习。
另一个观察:否则,方法 .predict()
将如何执行?我们最后只需要一个模型,而不是五个模型来进行预测
最终使用的模型,在整个数据集上拟合,你可以从以下提取:
search.best_estimator_
在一般情况下,这就是我们从数据集中保留一个测试集的原因。以评估我们的模型是否能很好地泛化
来自 scikit-learn:
3.1. 交叉验证:评估估计器性能
学习预测函数的参数并在相同的数据上测试它是一种方法论错误:一个仅仅重复它刚刚看到的样本标签的模型将会有完美的得分,但无法在未见过的数据上预测任何有用的东西。这种情况称为过拟合。