Sklearn:使用 CalibratedClassifierCV 校准多标签分类
Posted
技术标签:
【中文标题】Sklearn:使用 CalibratedClassifierCV 校准多标签分类【英文标题】:Sklearn: Calibrate a multi-label classification with CalibratedClassifierCV 【发布时间】:2022-01-20 02:22:40 【问题描述】:我已经构建了许多 sklearn 分类器模型来执行多标签分类,我想校准它们的 predict_proba
输出,以便获得置信度分数。我还想使用 sklearn.metrics.recall_score
等指标来评估它们。
我有 4 个标签要预测,真正的标签是多热编码的(例如[0, 1, 1, 1]
)。结果CalibratedClassifierCV
不直接接受我的数据:
clf = tree.DecisionTreeClassifier(max_depth=15)
clf = clf.fit(train_X, train_Y)
calibrated_clf = CalibratedClassifierCV(clf, cv="prefit", method="sigmoid")
calibrated_clf.fit(dev_X, dev_Y)
这会返回一个错误:
ValueError: classes [[0 1]
[0 1]
[0 1]
[0 1]] mismatch with the labels [0 1 2 3] found in the data
因此,我尝试将其包装在OneVsRestClassifier
:
clf = OneVsRestClassifier(tree.DecisionTreeClassifier(max_depth=15), n_jobs=4)
clf = clf.fit(train_X, train_Y)
calibrated_clf = CalibratedClassifierCV(clf, cv="prefit", method="sigmoid")
calibrated_clf.fit(dev_X, dev_Y)
请注意,MultiOutputClassifier
和 ClassifierChain
不起作用,即使它们可能更适合我的问题。
它可以工作,但由于its implementation,校准分类器的predict
输出是多类 而不是多标签。有四个类([0 1 2 3]
),但如果不需要贴标签,它仍然会预测为0
。
通过校准曲线进一步检查,结果发现包裹在校准分类器内的基本估计器根本没有校准。也就是说,(calibrated_clf.calibrated_classifiers_)[0].base_estimator
返回与校准前相同的clf
。
我想观察我的(校准的)模型在进行确定性 (predict
) 和概率性 (predict_proba
) 预测时的表现。我应该如何设计我的模型/将东西包装在其他容器中以获得每个标签的校准概率和可理解的标签预测?
【问题讨论】:
【参考方案1】:在您的示例中,您使用的是 DecisionTreeClassifier
,默认情况下,support targets 的维度为 (n, m),其中 m > 1。
但是,如果您想获得每个班级的 marginal probability 作为结果,请使用 OneVsRestClassifier.
请注意,CalibratedClassifierCV
需要 target to be 1d,因此“诀窍”是将其扩展为使用 MultiOutputClassifier 支持多标签分类。
完整示例
from sklearn.datasets import make_multilabel_classification
from sklearn.tree import DecisionTreeClassifier
from sklearn.multioutput import MultiOutputClassifier
from sklearn.model_selection import train_test_split, StratifiedKFold
import numpy as np
# Generate a sample multilabel target
X, y = make_multilabel_classification(n_classes=4, random_state=0)
y
>>>
array([[1, 0, 1, 0],
[0, 0, 0, 0],
[1, 0, 1, 0],
...
[0, 0, 0, 0],
[0, 1, 1, 1],
[1, 1, 0, 1]])
# Split in train/test
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.9, random_state=42
)
# Splits Stratify target variable
cv = StratifiedKFold(n_splits=2)
# Decision tree support by default multiclass target or use OneVsRest if marginal probabilities
clf = OneVsRestClassifier(DecisionTreeClassifier(max_depth=10))
# Calibrate estimator probabilities
calibrated_clf = CalibratedClassifierCV(base_estimator=clf, cv=cv)
# calibrated_clf target is one dimensional, extend classifier to multi-target classification.
multioutput_clf = MultiOutputClassifier(calibrated_clf).fit(X_train, y_train)
# Check predict
multioutput_clf.predict(X_test[-5:])
>>>
array([[0, 0, 1, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1]])
# Check predict_proba
multioutput_clf.predict_proba(X_test[-5:])
>>>
[array([[0.78333315, 0.21666685],
[0.78333315, 0.21666685],
[0.78333315, 0.21666685],
[0.78333315, 0.21666685],
[0.78333315, 0.21666685]]),
array([[0.59166537, 0.40833463],
[0.59166537, 0.40833463],
[0.40833361, 0.59166639],
[0.59166537, 0.40833463],
[0.59166537, 0.40833463]]),
array([[0.61666922, 0.38333078],
[0.61666427, 0.38333573],
[0.80000098, 0.19999902],
[0.61666427, 0.38333573],
[0.61666427, 0.38333573]]),
array([[0.26874774, 0.73125226],
[0.26874774, 0.73125226],
[0.45208444, 0.54791556],
[0.26874774, 0.73125226],
[0.26874774, 0.73125226]])]
注意predict_proba
的结果是一个包含 4 个数组的列表,每个数组是属于第 i 类的概率。例如,第一个数组的第一个样本里面是第一个样本属于第1类的概率等等。
关于校准曲线,scikit-learn 提供了为two dimension 和three dimension 目标绘制概率路径的示例。
【讨论】:
谢谢,校准后的模型现在可以提供所需格式的输出。校准模型的曲线比未校准的曲线更不稳定,校准后其性能变差。这是预期的行为吗? @ivsiquadrus 你在使用基于决策树的模型吗?在这种情况下,由于算法的性质,曲线会有点“不稳定”,预测往往围绕中心而不是极端 您如何评估校准? here 是使用 brier 分数的一个很好的例子 我明白了;我尝试在其他模型(例如 XGBoost 的梯度提升分类器)上重复绘制校准曲线和评估 F1 分数的过程,似乎校准对概率的提高相当小,并且确实对 F1 分数产生了负面影响(例如降低了 0.05-0.10 )。我使用 XGB 模型计算了所有四个标签的 Brier 分数,校准后的模型在除一个标签之外的所有标签中都有更高的 Brier 分数(高 0.001),校准似乎有效。以上是关于Sklearn:使用 CalibratedClassifierCV 校准多标签分类的主要内容,如果未能解决你的问题,请参考以下文章
当我应该使用其中之一时,“sklearn.cluster.k_means”和“sklearn.cluster.KMeans”有啥区别?