Sklearn:评估 GridSearchCV 中 OneVsRestClassifier 的每个分类器的性能
Sklearn: Evaluate performance of each classifier of OneVsRestClassifier inside GridSearchCV
我正在使用 OneVsRestClassifier
和 SVC
、
处理多标签分类
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]==fp
、gp.T[1]==sp
和gp.T[2]==tp
。所以 "global" 预测只是 'sequential' L
个人预测, 第二个问题已解决 .
但我仍然感到困惑,如果一个元分类器 OneVsRestClassifier
包含 L
个分类器,那么 GridSearchCV
returns 怎么可能只有一个最好的分数,对应于对于具有 L
个分类器的元分类器 OneVsRestClassifier
的 4*2*4 组参数之一?
如有任何评论,我们将不胜感激。
GridSearchCV
根据您的参数值创建网格,它将您的 OneVsRestClassifier
评估为原子 classifier(即 GridSearchCV
不知道这个 metaclass生成器)
首先:0.85是OneVsRestClassifier
参数[=16的所有可能组合(你的情况是16种组合,4*2*4)中最好的分数=],这意味着 GridSearchCV
评估 16(同样,仅在这种特殊情况下)可能 OneVsRestClassifier
,其中每个包含 L SVC
。一个 OneVsRestClassifier
中的所有 L class 化器都具有相同的参数值(但他们每个人都在学习从 L 可能中识别自己的 class)
即来自一组
{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 classifiers 的单独分数,但您可以查看实现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))
受@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
f1 scores for L
labels,每个标签都是二元任务的表现。最后,对L
f1 scores.
取平均(宏观或加权平均,由f1_score中的参数指定)得到单个分数。
然后GridSearchCV
在4*2*4组参数中选择最好的平均f1分数,在这个例子中是0.85。
虽然使用包装器解决多标签问题很方便,但它只能使用用于构建 L
分类器的同一组参数最大化平均 f1 分数。如果想分别优化每个标签的性能,似乎必须在不使用包装器的情况下构建 L
个分类器。
关于你的第二个问题,你可能想将 GridSearchCV
与 scikit-multilearn's BinaryRelevance classifier. Like OneVsRestClassifier
, Binary Relevance creates L single-label classifiers, one per label. For each label the training data is 1 if label is present and 0 if not present. The best selected classifier set is the BinaryRelevance
class instance in best_estimator_
property of GridSearchCV
. Use for predicting floats of probabilities use the predict_proba
method of the BinaryRelevance
object. An example can be found in the 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)
请注意,multi-label 分类的方法比二元相关性好得多 :) 您可以在 madjarov's comparison or my recent paper.
中找到它们
我正在使用 OneVsRestClassifier
和 SVC
、
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]==fp
、gp.T[1]==sp
和gp.T[2]==tp
。所以 "global" 预测只是 'sequential' L
个人预测, 第二个问题已解决 .
但我仍然感到困惑,如果一个元分类器 OneVsRestClassifier
包含 L
个分类器,那么 GridSearchCV
returns 怎么可能只有一个最好的分数,对应于对于具有 L
个分类器的元分类器 OneVsRestClassifier
的 4*2*4 组参数之一?
如有任何评论,我们将不胜感激。
GridSearchCV
根据您的参数值创建网格,它将您的 OneVsRestClassifier
评估为原子 classifier(即 GridSearchCV
不知道这个 metaclass生成器)
首先:0.85是OneVsRestClassifier
参数[=16的所有可能组合(你的情况是16种组合,4*2*4)中最好的分数=],这意味着 GridSearchCV
评估 16(同样,仅在这种特殊情况下)可能 OneVsRestClassifier
,其中每个包含 L SVC
。一个 OneVsRestClassifier
中的所有 L class 化器都具有相同的参数值(但他们每个人都在学习从 L 可能中识别自己的 class)
即来自一组
{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 classifiers 的单独分数,但您可以查看实现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))
受@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
f1 scores for L
labels,每个标签都是二元任务的表现。最后,对L
f1 scores.
然后GridSearchCV
在4*2*4组参数中选择最好的平均f1分数,在这个例子中是0.85。
虽然使用包装器解决多标签问题很方便,但它只能使用用于构建 L
分类器的同一组参数最大化平均 f1 分数。如果想分别优化每个标签的性能,似乎必须在不使用包装器的情况下构建 L
个分类器。
关于你的第二个问题,你可能想将 GridSearchCV
与 scikit-multilearn's BinaryRelevance classifier. Like OneVsRestClassifier
, Binary Relevance creates L single-label classifiers, one per label. For each label the training data is 1 if label is present and 0 if not present. The best selected classifier set is the BinaryRelevance
class instance in best_estimator_
property of GridSearchCV
. Use for predicting floats of probabilities use the predict_proba
method of the BinaryRelevance
object. An example can be found in the 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)
请注意,multi-label 分类的方法比二元相关性好得多 :) 您可以在 madjarov's comparison or my recent paper.
中找到它们