【问题标题】:GridSearchCV unexpected behaviour (always returns the first parameter as the best)GridSearchCV 意外行为(总是返回第一个参数为最佳)
【发布时间】:2021-12-18 15:05:47
【问题描述】:

我有一个多类分类问题,我需要找到最佳参数。我无法更改max_itersolvertol(它们是给定的),但我想检查哪个penalty 更好。但是,GridSearchCV 总是将第一个给定的罚分返回为最佳罚分。

例子:

from sklearn.model_selection import cross_val_score, GridSearchCV, StratifiedKFold
cv = StratifiedKFold(n_splits=5, random_state=0, shuffle=True)

fixed_params = {
    'random_state': 42,
    'multi_class': 'multinomial',
    'solver': 'saga',
    'tol': 1e-3,
    'max_iter': 500
}

parameters = [
    {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000], 'penalty': ['l1', 'l2', None]},
    {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000], 'penalty': ['elasticnet'], 'l1_ratio': np.arange(0.0, 1.0, 0.1)}     
]

model = GridSearchCV(LogisticRegression(**fixed_params), parameters, n_jobs=-1, verbose=10, scoring='f1_macro' ,cv=cv)
model.fit(X_train, y_train)

print(model.best_score_)
# 0.6836409100287101

print(model.best_params_)
# {'C': 0.1, 'penalty': 'l2'}

如果我更改parameters 行的顺序,结果将完全相反:

from sklearn.model_selection import cross_val_score, GridSearchCV, StratifiedKFold
cv = StratifiedKFold(n_splits=5, random_state=0, shuffle=True)
    
fixed_params = {
    'random_state': 42,
    'multi_class': 'multinomial',
    'solver': 'saga',
    'tol': 1e-3,
    'max_iter': 500
}

parameters = [
        {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000], 'penalty': ['elasticnet'], 'l1_ratio': np.arange(0.0, 1.0, 0.1)} 
        {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000], 'penalty': ['l1', 'l2', None]}          
]
    
model = GridSearchCV(LogisticRegression(**fixed_params), parameters, n_jobs=-1, verbose=10, scoring='f1_macro' ,cv=cv)
model.fit(X_train, y_train)

print(model.best_score_)
# 0.6836409100287101

print(model.best_params_)
# {'C': 0.1, 'l1_ratio': 0.0, 'penalty': 'elasticnet'}

因此,best_score_ 对于两个选项是相同的,但 best_params_ 不是。

你能告诉我有什么问题吗?

已编辑
与使用默认参数的基线相比,GridSearchCV 的结果更差。
基线:

baseline_model = LogisticRegression(multi_class='multinomial', solver='saga', tol=1e-3, max_iter=500)
baseline_model.fit(X_train, y_train)
train_pred_baseline = baseline_model.predict(X_train)
print(f1_score(y_train, train_pred_baseline, average='micro'))

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=真, 拦截缩放=1,l1_ratio=无,max_iter=500, multi_class='多项式',n_jobs=无,惩罚='l2', random_state=None,solver='saga',tol=0.001,verbose=0, warm_start=False)

Baseline 给我的 f1_micro 比 GridSearchCV 更好:

0.7522768670309654
 

Edited-2
因此,根据最佳f1_score 性能,C = 1 是我模型的最佳选择。但是 GridSearchCV 返回我C = 0.1。 我想,我想念一些东西...
Baseline 的 f1_macro 也比 GridSearchCV 好:

    train_pred_baseline = baseline_model.predict(X_train)
    print(f1_score(y_train, train_pred_baseline, average='macro'))
    # 0.7441968750050458

【问题讨论】:

  • 你可以尝试通过查看所有 GridSearch 的结果来调试它(检查model.cv_results_)。

标签: python scikit-learn logistic-regression gridsearchcv


【解决方案1】:

其实并没有错。事情就是这样。 Elasticnet 使用 L1 和 L2 惩罚项。但是,如果您的 l1_ratio 为 0,那么您基本上是在应用 L2 正则化,因此您只使用 L2 惩罚项。如文档中所述:

设置l1_ratio=0相当于使用penalty='l2',而设置l1_ratio=1相当于使用penalty='l1'。对于0 < l1_ratio <1,惩罚是 L1 和 L2 的组合。

由于您的第二个结果 l1_ratio 为 0,因此相当于使用 L2 惩罚项。

【讨论】:

  • 你能告诉我,为什么 GridSearchCV 给我的 f1_score 比基线差吗? (我编辑了我的问题)。
  • 使用默认设置,我的 f1 score_micro = 0.75,但在 GridSearchCV 之后只有 0.68。基线也更适合我的测试样本...
  • 您使用f1_macro 作为网格搜索的记分员,但您的基线使用f1_micro。还要考虑到网格搜索使用交叉验证,因此部分训练集被保留在每个 CV 拆分中,其中保留的样本被评分和平均。
  • 我的错,但问题仍然在我身上,f1_macro 也更适合基线。
  • 更改 CV 参数是个好主意吗?
猜你喜欢
  • 2015-04-06
  • 2014-11-14
  • 1970-01-01
  • 2020-04-25
  • 2015-09-30
  • 2021-11-24
  • 2023-01-28
  • 2021-11-17
  • 2017-05-14
相关资源
最近更新 更多