Sklearn:评估 GridSearchCV 中 OneVsRestClassifier 的每个分类器的性能

Posted

技术标签:

【中文标题】Sklearn:评估 GridSearchCV 中 OneVsRestClassifier 的每个分类器的性能【英文标题】:Sklearn: Evaluate performance of each classifier of OneVsRestClassifier inside GridSearchCV 【发布时间】:2016-02-20 09:13:35 【问题描述】:

我正在使用OneVsRestClassifierSVC 处理多标签分类,

from sklearn.datasets import make_multilabel_classification
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.grid_search import GridSearchCV

L=3
X, y = make_multilabel_classification(n_classes=L, n_labels=2,
                                  allow_unlabeled=True,
                                  random_state=1, return_indicator=True)    
model_to_set = OneVsRestClassifier(SVC())

parameters = 
    "estimator__C": [1,2,4,8],
    "estimator__kernel": ["poly","rbf"],
    "estimator__degree":[1, 2, 3, 4],


model_tunning = GridSearchCV(model_to_set, param_grid=parameters,
                             scoring='f1')

model_tunning.fit(X, y)

print model_tunning.best_score_
print model_tunning.best_params_

#0.855175822314
#'estimator__kernel': 'poly', 'estimator__C': 1, 'estimator__degree': 3

第一个问题

0.85 代表什么数字?它是L 分类器中的最高分还是平均分?同样,这组参数是否代表L 分类器中得分最高的?

第二个问题

基于这样一个事实,如果我是对的,OneVsRestClassifier 确实为每个标签构建了L 分类器,人们可以期望访问或观察每个标签的性能。但是,在上面的例子中,如何从GridSearchCV 对象中获取L 分数呢?

编辑

为了简化问题并帮助自己更多地了解OneVsRestClassifier,在调整模型之前,

model_to_set.fit(X,y)
gp = model_to_set.predict(X) # the "global" prediction
fp = model_to_set.estimators_[0].predict(X) # the first-class prediction
sp = model_to_set.estimators_[1].predict(X) # the second-class prediction
tp = model_to_set.estimators_[2].predict(X) # the third-class prediction

可以证明gp.T[0]==fpgp.T[1]==spgp.T[2]==tp。因此,“全局”预测只是“连续”L 个人预测,第二个问题已解决

但我仍然感到困惑的是,如果一个元分类器 OneVsRestClassifier 包含 L 分类器,GridSearchCV 怎么可能只返回一个最好的分数,对应于 4*2*4 组参数之一,对于具有L 分类器的元分类器OneVsRestClassifier

很高兴看到任何评论。

【问题讨论】:

【参考方案1】:

至于您的第二个问题,您可能希望将GridSearchCV 与scikit-multilearn 的BinaryRelevance 分类器一起使用。与OneVsRestClassifier 一样,Binary Relevance 创建了 L 个单标签分类器,每个标签一个。对于每个标签,如果标签存在,则训练数据为 1,如果不存在,则为 0。最佳选择的分类器集是GridSearchCVbest_estimator_ 属性中的BinaryRelevance 类实例。使用BinaryRelevance 对象的predict_proba 方法来预测概率浮点数。可以在scikit-multilearn docs for model selection 中找到一个示例。

在您的情况下,我将运行以下代码:

from skmultilearn.problem_transform import BinaryRelevance
from sklearn.model_selection import GridSearchCV
import sklearn.metrics

model_to_set = BinaryRelevance(SVC())

parameters = 
    "classifier__estimator__C": [1,2,4,8],
    "classifier__estimator__kernel": ["poly","rbf"],
    "classifier__estimator__degree":[1, 2, 3, 4],


model_tunning = GridSearchCV(model_to_set, param_grid=parameters,
                             scoring='f1')

model_tunning.fit(X, y)

# for some X_test testing set
predictions = model_tunning.best_estimator_.predict(X_test)

# average=None gives per label score
metrics.f1_score(y_test, predictions, average = None) 

请注意,多标签分类方法比二元相关性要好得多:) 您可以在 madjarov's comparison 或 my recent paper 中找到它们。

【讨论】:

【参考方案2】:

受@Olologin 回答的启发,我意识到0.85 是L 预测获得的f1 分数(在此示例中)的最佳加权平均值。在以下代码中,我通过内部测试评估模型,使用 f1 分数的宏观平均值:

# Case A, inspect F1 score using the meta-classifier
F_A = f1_score(y, model_tunning.best_estimator_.predict(X), average='macro')

# Case B, inspect F1 scores of each label (binary task) and collect them by macro average
F_B = []
for label, clc in zip(y.T, model_tunning.best_estimator_.estimators_):
    F_B.append(f1_score(label, clf.predict(X)))
F_B = mean(F_B)

F_A==F_B # True

因此这意味着GridSearchCV 应用 4*2*4 组参数之一来构建元分类器,然后使用L 分类器之一对每个标签进行预测。结果将为L 标签的L f1 分数,每个标签都是二元任务的性能。最后,对L f1 分数取平均值(宏观或加权平均,由 f1_score 中的参数指定)得到单个分数。

GridSearchCV 然后在 4*2*4 组参数中选择最好的平均 f1 分数,在本例中为 0.85。

虽然对于多标签问题使用包装器很方便,但它只能使用用于构建L 分类器的相同参数集来最大化平均 f1 分数。如果要分别优化每个标签的性能,似乎必须在不使用包装器的情况下构建L 分类器。

【讨论】:

> 如果想分别优化每个标签的性能,似乎必须在不使用包装器的情况下构建 L 个分类器。是的,你没看错。 谢谢!所以在我看来,如果每个类的优化不是主要问题,应该使用包装器。因为除了方便和方便之外,使用包装器和手动构建L 模型没有其他区别。【参考方案3】:

GridSearchCV 从您的参数值创建网格,它将您的 OneVsRestClassifier 评估为原子分类器(即GridSearchCV 不知道此元分类器中的内容)

第一:0.85是OneVsRestClassifier在参数("estimator__C", "estimator__kernel", "estimator__degree")的所有可能组合(你的情况下是16种组合,4*2*4)中最好的分数,这意味着GridSearchCV评估 16 个(同样,仅在这种特殊情况下)可能的OneVsRestClassifier,每个都包含 L SVC。一个OneVsRestClassifier 中的所有 L 个分类器都具有相同的参数值(但每个分类器都在学习从 L 个可能中识别自己的类)

即从一组

OneVsRestClassifier(SVC(C=1, kernel="poly", degree=1)),
 OneVsRestClassifier(SVC(C=1, kernel="poly", degree=2)),
 ...,
 OneVsRestClassifier(SVC(C=8, kernel="rbf", degree=3)),
 OneVsRestClassifier(SVC(C=8, kernel="rbf", degree=4))

它选择得分最高的一个。

model_tunning.best_params_ 此处表示 OneVsRestClassifier(SVC()) 的参数,通过它可以实现model_tunning.best_score_。 你可以从model_tunning.best_estimator_ 属性中获得最好的OneVsRestClassifier

第二:没有现成的代码可以从OneVsRestClassifier获得L分类器的单独分数,但是您可以查看OneVsRestClassifier.fit方法的实现,或者采取这个(应该工作: ) ):

# Here X, y - your dataset
one_vs_rest = model_tunning.best_estimator_
yT = one_vs_rest.label_binarizer_.transform(y).toarray().T
# Iterate through all L classifiers
for classifier, is_ith_class in zip(one_vs_rest.estimators_, yT):
    print(classifier.score(X, is_ith_class))

【讨论】:

谢谢!在第一个中,集合中有 4*2*4 个OneVsRestClassifiers,每个都对应于使用同一组参数的L 分类器。所以我想知道为什么一组参数只有一个分数而不是L 分数。 0.85 是 4*2*4*L 模型中最好的分数吗? @Francis,不,0.85 是 4*2*4 OneVsRestClassifier 中最好的分数(因为这个分类器有 4*2*4 的参数组合)。 GridSearchCV 只是在每个可能的组合上评估 OneVsRestClassifier 并选择一个准确度最高的组合。您可以从 GridSearchCV 的 grid_scores_ 属性中获取所有可能的参数组合和相应的分数,但是如果您想从每个 OneVsRestClassifier 中分离 L 分类器的分数(所以它是 4*2*4*L 分数) - 您应该编写自己的代码。对不起,我的英语可能从我试图解释的内容中不清楚。 不,实际上是我的英语不好,因为我不是母语人士:)。我想我弄清楚了 GridSearchCV 在元分类器上的行为,请帮我澄清答案,谢谢!

以上是关于Sklearn:评估 GridSearchCV 中 OneVsRestClassifier 的每个分类器的性能的主要内容,如果未能解决你的问题,请参考以下文章

如何在交叉验证和 GridSearchCV 中实现 SMOTE

你能从 sklearn 网格搜索 (GridSearchCV) 中获得所有估计器吗?

GridsearchCV sklearn 中的错误

sklearn - 如何从传递给 GridSearchCV 的管道中检索 PCA 组件和解释方差

如何实现 sklearn 的 Estimator 接口以在 GridSearchCV 管道中使用?

如何在 python 中的 sklearn 中获取 GridSearchCV 中的选定功能