Sklearn:评估GridSearchCV

时间:2015-11-18 15:00:24

标签: python scikit-learn multilabel-classification grid-search

我正在处理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分类器,可以期望访问或观察每个标签的性能。但是,在上面的例子中,如何从L对象获得GridSearchCV分数?

修改

在调整模型之前,要简化问题并帮助自己了解有关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组参数,对于具有OneVsRestClassifier分类器的元分类器L

看到任何评论都会非常感激。

3 个答案:

答案 0 :(得分:4)

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

首先:0.85是所有可能组合(在您的情况下为16个组合,4 * 2 * 4)参数OneVsRestClassifier("estimator__C", "estimator__kernel", "estimator__degree")的最高分,这意味着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_。 您可以从OneVsRestClassifier属性获得最佳model_tunning.best_estimator_

第二:没有准备好使用代码从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))

答案 1 :(得分:3)

受@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分类器。

答案 2 :(得分:1)

关于您的第二个问题,您可能希望将GridSearchCVscikit-multilearn BinaryRelevance分类器一起使用。与OneVsRestClassifier类似,二进制相关性创建L个单标签分类器,每个标签一个。对于每个标签,如果存在标签,则训练数据为1,如果不存在则为0。最佳选择的分类器集是BinaryRelevance best_estimator_属性中的GridSearchCV类实例。用于预测概率浮点值的方法使用predict_proba对象的BinaryRelevance方法。可以在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 comparisonmy recent paper中找到它们。