使用 OneVsRestClassifier 的分类目标和单热编码目标之间的概率差异

probability difference between categorical target and one-hot encoding target using OneVsRestClassifier

与来自 sklean 的 OneVsRestClassifier 的分类目标和单热编码目标之间的概率有点混淆。以虹膜数据和简单逻辑回归为例。当我使用原始虹膜 class[0,1,2] 时,计算出的每次观察的 OneVsRestClassifier() 概率总和为 1。但是,如果我将目标转换为假人,则情况并非如此。我知道 OneVsRestClassifier() 比较 one 与 rest(class 0 与非 class 0,class 1 与非 class 1,等等)。这些概率的总和与 1 没有关系更有意义。那么为什么我看到差异以及如何差异?

import numpy as np
import pandas as pd
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
np.set_printoptions(suppress=True)

iris = datasets.load_iris()
rng = np.random.RandomState(0)
perm = rng.permutation(iris.target.size)
X = iris.data[perm]
y = iris.target[perm]

# categorical target with no conversion

X_train, y_train1 = X[:80], y[:80]
X_test, y_test1 = X[80:], y[80:]

m3 = LogisticRegression(random_state=0)
clf1 = OneVsRestClassifier(m3).fit(X_train, y_train1)
y_pred1 = clf1.predict(X_test)
print(np.sum(y_pred1 == y_test))
y_prob1 = clf1.predict_proba(X_test)
y_prob1[:5]

#output
    array([[0.00014508, 0.17238549, 0.82746943],
           [0.03850173, 0.79646817, 0.1650301 ],
           [0.73981106, 0.26018067, 0.00000827],
           [0.00016332, 0.32231163, 0.67752505],
           [0.00029197, 0.2495404 , 0.75016763]])

# one hot encoding for categorical target

y2 = pd.get_dummies(y)
y_train2 = y2[:80]
y_test2 = y2[80:]
clf2 = OneVsRestClassifier(m3).fit(X_train, y_train2)
y_pred2 = clf2.predict(X_test)
y_prob2 = clf2.predict_proba(X_test)
y_prob2[:5]

#output
array([[0.00017194, 0.20430011, 0.98066319],
       [0.02152246, 0.44522562, 0.09225181],
       [0.96277892, 0.3385952 , 0.00001076],
       [0.00023024, 0.45436925, 0.95512082],
       [0.00036849, 0.31493725, 0.94676348]])

当您对目标进行编码时,sklearn 将您的问题解释为一个 multilabel 而不仅仅是 multiclass;也就是说,一个点可能有多个真实标签。在这种情况下,概率总和大于(或小于)1 是完全可以接受的。sklearn 通常是这样,但 OneVsRestClassifier 在文档字符串中特别指出:

OneVsRestClassifier can also be used for multilabel classification. To use this feature, provide an indicator matrix for the target y when calling .fit.

至于第一种方法,确实有三个独立的模型,但预测是归一化的;参见 the source code。事实上,这是唯一的区别:

(y_prob2 / y_prob2.sum(axis=1)[:, None] == y_prob1).all()

# output
True

可能值得指出的是 LogisticRegression 也原生支持 multiclass。在那种情况下,每个 class 的权重是独立的,因此它类似于三个独立的模型,但得到的概率是 softmax 应用程序的结果,并且损失函数最小化每个 class 的损失同时,因此得到的系数和预测可能与从 OneVsRestClassifier:

获得的系数不同
m3.fit(X_train, y_train1)
y_prob0 = m3.predict_proba(X_test)
y_prob0[:5]

# output:
array([[0.00000494, 0.01381671, 0.98617835],
       [0.02569699, 0.88835451, 0.0859485 ],
       [0.95239985, 0.04759984, 0.00000031],
       [0.00001338, 0.04195642, 0.9580302 ],
       [0.00002815, 0.04230022, 0.95767163]])