我正在使用Sci Kit学习一个分类问题,并且困惑于如何正确地调优超参数以获得“最佳”模型。
Before任何调整,我的logistic回归分类器对测试集的准确率为74.6%。
为了为我的最终模型选择最优的参数,我用一个参数网格来拟合一个GridSearchCV对象-- to --我的训练数据,其中包含了Sci Kit学习的LogisticRegression分类器的默认参数。
我所拟合的GridSearchCV模型的CV精度为76.5%,表明该模型将比未调优模型具有更高的精度。
When --我在测试集上拟合并评估了调优模型,我的准确率为73%。
这是让我感到困惑的部分。我知道CV的结果应该用来估计模型的性能,但是它实际上降低了测试的准确性。
这是否意味着我应该继续使用通过GridSearchCV找到的“最佳”模型,还是应该使用未调优的模型,因为它在测试集上具有更高的精度?
使用的<#>Code (不能提供数据)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
# Split the data
X = data.drop(columns=target)
y = data[target]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10)
# Define different Pipelines for Numeric vs. Categorical
numeric_transformer = Pipeline(
steps=[
("numeric_imputer", SimpleImputer(strategy="mean")),
("scaler", StandardScaler())
]
)
categorical_transformer = Pipeline(
steps=[
("categorical_imputer", SimpleImputer(strategy="most_frequent")),
("ohe", OneHotEncoder(handle_unknown="ignore"))
]
)
numeric_features = X_train.select_dtypes(include="number").columns.values
categorical_features = X_train.select_dtypes(exclude="number").columns.values
# Combine into single preprocessor
preprocessor = ColumnTransformer(
transformers=[
("cat", categorical_transformer, categorical_features),
("num", numeric_transformer, numeric_features),
]
)
# Score the model before tuning parameters
steps = [
('preprocessor', preprocessor),
('regressor', LogisticRegression())
]
pipeline = Pipeline(steps)
pipeline.fit(X_train, y_train)
accuracy = pipeline.score(X_test, y_test)
print(f"Test Accuracy before Hyperparamter Tuning\n{accuracy:,}")
##############################################################################
# Model Tuning
steps = [
('preprocessor', preprocessor),
('regressor', LogisticRegression())
]
pipeline = Pipeline(steps)
# Set up the parameter grid to search over
param_grid = {
"regressor__solver": ['newton-cg', 'lbfgs', 'liblinear'],
"regressor__penalty": ['l1', 'l2', 'elasticnet'],
"regressor__C": [100, 10, 1.0, 0.1, 0.01],
"regressor__fit_intercept": [False, True]
}
cv = GridSearchCV(pipeline
, cv = 4
, param_grid=param_grid
, scoring='accuracy')
cv.fit(X_train, y_train)
accuracy = cv.score(X_train, y_train)
print(f"Hyperparamter Tuned Model CV Accuracy\n{accuracy:,}")
print(f"Tuned Model Best Params: {cv.best_params_}")
# Final Test of Tuned model
cv.best_estimator_.fit(X_train, y_train)
accuracy = cv.best_estimator_.score(X_test, y_test)
print(f"Test Accuracy before Hyperparamter Tuning\n{accuracy:,}")以上代码的Result

编辑:
我发现,如果我将GridSearchCV对象适合于整个数据集(而不是仅训练数据),那么从GridSearchCV对象返回的“最佳”模型实际上是一个具有默认参数的LogisticRegression分类器。
我记得我读到,简历应该应用到培训集中,只用于选择一个模型,这样您就可以使用测试集作为所选模型的最终验证。
^这是正确的方法吗,还是应该使用所有数据的简历来选择我的模型?
我知道引擎盖下的简历已经把数据分割成了训练和测试集,但我认为你还想在这个过程之外留下一个最终的测试集?
发布于 2023-02-22 07:52:12
在sklearn中,用于网格搜索的k折叠交叉验证(CV)确实将提供给网格搜索的数据集划分为k (通常为5,这是默认的)折叠。在您的例子中,k = 4,因为您指定了cv = 4。
在培训过程中,这四个折叠中的每一个都曾被用作验证集(与测试集不同),其余的时间则是培训集的一部分。根据网格搜索中的交叉验证过程,选择最优模型,并在所有4倍上进行训练,最终得到经过训练的模型。
由于提供给网格搜索的所有数据都用作模型和超参数优化的训练数据,因此不能使用这些数据来无偏地评估模型的性能。相反,需要一个既不用于调优超参数,也不用于训练模型的持久测试集。使用该测试集,可以对模型的精度进行最终的、无偏的评估。
在你的例子中,0.7306667的精度是模型精度的正确估计,而0.7653334是训练集的精度,并不反映它是否也能在新的、看不见的数据上实现。因此,坚持在X_train和y_train上运行D3和D4的方法,然后在X_test和y_test上计算经过训练的模型的准确性。
https://datascience.stackexchange.com/questions/118700
复制相似问题