sklearn 使用带有自定义指标的 RandomizedSearchCV 并捕获异常

Posted

技术标签:

【中文标题】sklearn 使用带有自定义指标的 RandomizedSearchCV 并捕获异常【英文标题】:sklearn use RandomizedSearchCV with custom metrics and catch Exceptions 【发布时间】:2019-05-11 08:53:54 【问题描述】:

我在 sklearn 中使用带有随机森林分类器的 RandomizedSearchCV 函数。 要查看不同的指标,我正在使用自定义评分

from sklearn.metrics import make_scorer, roc_auc_score, recall_score, matthews_corrcoef, balanced_accuracy_score, accuracy_score

acc = make_scorer(accuracy_score)

auc_score = make_scorer(roc_auc_score)
recall = make_scorer(recall_score)
mcc = make_scorer(matthews_corrcoef)
bal_acc = make_scorer(balanced_accuracy_score)

scoring = "roc_auc_score": auc_score, "recall": recall, "MCC" : mcc, 'Bal_acc' : bal_acc, "Accuracy": acc 

这些自定义记分器用于随机搜索

rf_random = RandomizedSearchCV(estimator=rf, param_distributions=random_grid, n_iter=100, cv=split, verbose=2,
                               random_state=42, n_jobs=-1, error_score=np.nan, scoring = scoring, iid = True, refit="roc_auc_score")

现在的问题是,当我使用自定义拆分时,AUC 会抛出异常,因为这个精确拆分只有一个类标签。

我不想更改拆分,因此是否有可能在 RandomizedSearchCV 或 make_scorer 函数中捕获这些异常? 所以例如如果没有计算其中一个指标(由于异常),只需输入 NaN 并继续下一个模型。

编辑: 显然,error_score 不包括模型训练,但不包括度量计算。如果我使用例如 Accuracy 一切正常,我只会在只有一个类标签的折叠处收到警告。如果我使用例如 AUC 作为指标,我仍然会抛出异常。

如果能在这里得到一些想法会很棒!

解决方案: 定义自定义记分器有例外:

def custom_scorer(y_true, y_pred, actual_scorer):
score = np.nan

try:
  score = actual_scorer(y_true, y_pred)
except ValueError: 
  pass

return score

这导致了一个新的指标:

acc = make_scorer(accuracy_score)
recall = make_scorer(custom_scorer, actual_scorer=recall_score)
new_auc = make_scorer(custom_scorer, actual_scorer=roc_auc_score)
mcc = make_scorer(custom_scorer, actual_scorer=matthews_corrcoef)
bal_acc = make_scorer(custom_scorer,actual_scorer=balanced_accuracy_score)

scoring = "roc_auc_score": new_auc, "recall": recall, "MCC" : mcc, 'Bal_acc' : bal_acc, "Accuracy": acc 

这又可以传递给RandomizedSearchCV的打分参数

我找到的第二个解决方案是:

def custom_auc(clf, X, y_true):
score = np.nan
y_pred = clf.predict_proba(X)
try:
    score = roc_auc_score(y_true, y_pred[:, 1])
except Exception:
    pass

return score

也可以传递给打分参数:

scoring = "roc_auc_score": custom_auc, "recall": recall, "MCC" : mcc, 'Bal_acc' : bal_acc, "Accuracy": acc 

(改编自this answer)

【问题讨论】:

不完全清楚你想要什么。您正在使用error_score=np.nan,它将满足您的要求。您还需要什么,还是没有按预期工作? 我添加了上面的问题。基本上它没有按预期工作,因为即使有 error_score 我也得到了异常 哦,是的,我的错。 error_score 将仅覆盖 estimator.fit()。你能举个“the AUC is throwing an exception because there is only one class label for this exact split.”的例子吗? “ValueError:y_true 中只有一个类。在这种情况下未定义 ROC AUC 分数”将是我得到的例外(到目前为止)。 【参考方案1】:

您可以拥有一个通用记分器,它可以将其他记分器作为输入,检查结果,捕捉它们抛出的任何异常并返回一个固定值。

def custom_scorer(y_true, y_pred, actual_scorer):
    score = np.nan

    try:
      score = actual_scorer(y_true, y_pred)
    except Exception: 
      pass

    return score

然后你可以使用:

acc = make_scorer(custom_scorer, actual_scorer = accuracy_score)
auc_score = make_scorer(custom_scorer, actual_scorer = roc_auc_score, 
                        needs_threshold=True) # <== Added this to get correct roc
recall = make_scorer(custom_scorer, actual_scorer = recall_score)
mcc = make_scorer(custom_scorer, actual_scorer = matthews_corrcoef)
bal_acc = make_scorer(custom_scorer, actual_scorer = balanced_accuracy_score)

重现示例:

import numpy as np
def custom_scorer(y_true, y_pred, actual_scorer):
    score = np.nan

    try:
      score = actual_scorer(y_true, y_pred)
    except Exception: 
      pass

    return score


from sklearn.metrics import make_scorer, roc_auc_score, accuracy_score
acc = make_scorer(custom_scorer, actual_scorer = accuracy_score)
auc_score = make_scorer(custom_scorer, actual_scorer = roc_auc_score, 
                        needs_threshold=True) # <== Added this to get correct roc

from sklearn.datasets import load_iris
X, y = load_iris().data, load_iris().target

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV, KFold
cvv = KFold(3)
params='criterion':['gini', 'entropy']
gc = GridSearchCV(DecisionTreeClassifier(), param_grid=params, cv =cvv, 
                  scoring="roc_auc": auc_score, "accuracy": acc, 
                  refit="roc_auc", n_jobs=-1, 
                  return_train_score = True, iid=False)
gc.fit(X, y)
print(gc.cv_results_)

【讨论】:

我在这里看到了您的想法并喜欢解决方法。不幸的是,它失败了:在 get return _ForkingPickler.loads(res) A​​ttributeError: Can't get attribute 'custom_scorer' 稍后在堆栈跟踪中:一个任务未能取消序列化。请确保函数的参数都是可挑选的。使用 n_jobs = 1 运行它可以正常工作,所以我猜这是多线程的问题。 @JennyH 即使使用n_jobs=-1,我也没有收到任何错误。您是否在另一个文件中定义了记分器并尝试将其导入或在同一个文件中?我已经更新了有效的最小示例。 我们开始了。我还有 scikit-learn 0.20.0。更新到 0.20.1 有所帮助,现在它的工作就像一个魅力。抱歉,感谢 MWE! 我让它在一夜之间运行,不幸的是我再次抛出异常:如果我将 predict_proba=True 与 AUC 一起使用(不是阈值,因为 auc 不需要,并且也会给出错误)我再次结束: ValueError: got predict_proba of shape (96, 1),但需要具有两个类的分类器来进行 custom_scorer 评分

以上是关于sklearn 使用带有自定义指标的 RandomizedSearchCV 并捕获异常的主要内容,如果未能解决你的问题,请参考以下文章

Sklearn:具有字符串值和自定义指标的最近邻

sklearn基于make_scorer函数构建自定义损失函数或者评估指标

Kubernetes HPA(带有自定义指标)扩展策略

Sklearn kNN 使用用户定义的指标

GridSearchCV 的 sklearn 中的自定义“k 精度”评分对象

带有自定义指标的 DBSCAN