使用支持向量机预测概率

11

我编写了这段代码,希望获得分类的概率。

from sklearn import svm
X = [[0, 0], [10, 10],[20,30],[30,30],[40, 30], [80,60], [80,50]]
y = [0, 1, 2, 3, 4, 5, 6]
clf = svm.SVC() 
clf.probability=True
clf.fit(X, y)
prob = clf.predict_proba([[10, 10]])
print prob
我得到了这个输出:
[[0.15376986 0.07691205 0.15388546 0.15389275 0.15386348 0.15383004 0.15384636]]

这很奇怪,因为概率本应该是

[0 1 0 0 0 0 0 0]

请注意,需要预测类别的样本与第二个样本相同。此外,为该类别计算得到的概率最低。


概率应该加起来等于1。这并不意味着它们应该是0或1!您可以使用argmax选择最高的概率。在您的情况下,6个类的概率是相等的。因此,它可以属于任何一个类,但不属于第1类。 - Hadij
3个回答

8

您应该禁用 probability 并使用 decision_function,因为不能保证 predict_probapredict 返回相同的结果。 您可以在这里阅读更多关于此的内容:文档

clf.predict([[10, 10]]) // returns 1 as expected 

prop = clf.decision_function([[10, 10]]) // returns [[ 4.91666667  6.5         3.91666667  2.91666667  1.91666667  0.91666667
      -0.08333333]]
prediction = np.argmax(prop) // returns 1 

你的答案可能没有华丽的图表,但对我来说是最有用的。我只想补充一点,就是你可以将 decision_function 的输出应用 softmax 函数,将其转换为概率值,这正是用户所要求的。 - Kailegh
@Kailegh,感谢您的反馈。如果您能给我一个赞,我将不胜感激。 - Tim
1
抱歉,给你了!=D - Kailegh

8
编辑: 正如@TimH所指出的那样,可以通过clf.decision_function(X)给出概率。下面的代码已经修正了这个问题。predict_proba(X)的预测概率存在低概率的问题。根据官方文档here的解释,问题在于:"...它将在非常小的数据集上产生无意义的结果"。

关键是理解SVM的结果概率。简而言之,在2D平面上你有7个类别和7个点。SVM试图找到一个线性分离器,以区分每个类别和其他每个类别(一对一的方法)。每次只选择两个类别。结果是归一化后的分类器投票结果。更详细的多类SVMs解释可以参考this(英文)或here (scikit-learn使用libsvm)。

稍加修改您的代码,我们可以看到确实选择了正确的类:

from sklearn import svm
import matplotlib.pyplot as plt
import numpy as np


X = [[0, 0], [10, 10],[20,30],[30,30],[40, 30], [80,60], [80,50]]
y = [0, 1, 2, 3, 3, 4, 4]
clf = svm.SVC() 
clf.fit(X, y)

x_pred = [[10,10]]
p = np.array(clf.decision_function(x_pred)) # decision is a voting function
prob = np.exp(p)/np.sum(np.exp(p),axis=1, keepdims=True) # softmax after the voting
classes = clf.predict(x_pred)

_ = [print('Sample={}, Prediction={},\n Votes={} \nP={}, '.format(idx,c,v, s)) for idx, (v,s,c) in enumerate(zip(p,prob,classes))]

相应的输出为:
Sample=0, Prediction=0,
Votes=[ 6.5         4.91666667  3.91666667  2.91666667  1.91666667  0.91666667 -0.08333333] 
P=[ 0.75531071  0.15505748  0.05704246  0.02098475  0.00771986  0.00283998  0.00104477], 
Sample=1, Prediction=1,
Votes=[ 4.91666667  6.5         3.91666667  2.91666667  1.91666667  0.91666667 -0.08333333] 
P=[ 0.15505748  0.75531071  0.05704246  0.02098475  0.00771986  0.00283998  0.00104477], 
Sample=2, Prediction=2,
Votes=[ 1.91666667  2.91666667  6.5         4.91666667  3.91666667  0.91666667 -0.08333333] 
P=[ 0.00771986  0.02098475  0.75531071  0.15505748  0.05704246  0.00283998  0.00104477], 
Sample=3, Prediction=3,
Votes=[ 1.91666667  2.91666667  4.91666667  6.5         3.91666667  0.91666667 -0.08333333] 
P=[ 0.00771986  0.02098475  0.15505748  0.75531071  0.05704246  0.00283998  0.00104477], 
Sample=4, Prediction=4,
Votes=[ 1.91666667  2.91666667  3.91666667  4.91666667  6.5         0.91666667 -0.08333333] 
P=[ 0.00771986  0.02098475  0.05704246  0.15505748  0.75531071  0.00283998  0.00104477], 
Sample=5, Prediction=5,
Votes=[ 3.91666667  2.91666667  1.91666667  0.91666667 -0.08333333  6.5  4.91666667] 
P=[ 0.05704246  0.02098475  0.00771986  0.00283998  0.00104477  0.75531071  0.15505748], 
Sample=6, Prediction=6,
Votes=[ 3.91666667  2.91666667  1.91666667  0.91666667 -0.08333333  4.91666667  6.5       ] 
P=[ 0.05704246  0.02098475  0.00771986  0.00283998  0.00104477  0.15505748  0.75531071], 

您可以看到决策区域:

X = np.array(X)
y = np.array(y)
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)

XX, YY = np.mgrid[0:100:200j, 0:100:200j]
Z = clf.predict(np.c_[XX.ravel(), YY.ravel()])

Z = Z.reshape(XX.shape)
plt.figure(1, figsize=(4, 3))
plt.pcolormesh(XX, YY, Z, cmap=plt.cm.Paired)

for idx in range(7):
    ax.scatter(X[idx,0],X[idx,1], color='k')

enter image description here


1
@PKlumpp 谢谢,已经添加了关于概率的注释。 - mr_mo
我认为这个答案不正确。你所谓的概率并不是真正的概率。在decision_function文档中提到了这篇文章,其中解释了原因。同样,在这份文件的第4页中也说,通过softmax将决策函数映射到概率的方法“并没有很好的基础”。 - Manuel
SVC() 中,decision_function_shape 的默认值是 'ovr',这意味着它返回一个形状为 (n_samples, n_classes) 的一对多('ovr')决策函数,就像所有其他分类器一样。在此演示中,标签空间为 [0, 1, 2, 3],因此 n_classes = 4。那么为什么 P 包含 7 个结果?这是我从 sklearn=0.24.1 得到的结果: Votes=[ 3.16124317 3.19468064 0.87106327 3.17454938 -0.24583347] P=[0.31428908 0.32497579 0.03182122 0.31849903 0.01041489],``` 谢谢。 - GuokLiu
@GuokLiu 实际上有5个类别。关于P值,它是样本数量和每个样本的“概率”。 - mr_mo
感谢您及时回复,@mr_mo。是的,标签空间为[0, 1, 2, 3, 4],n_classes = 5。我认为用 x_pred = X 替换 x_pred = [[10,10]] 可能更清晰。这将匹配所示的输出:) - GuokLiu
显示剩余4条评论

2
你可以在文档中阅读到...
SVC方法的decision_function为每个样本(或在二分类情况下为每个样本提供单个分数)提供每个类别的分数。当构造函数选项probability设置为True时,启用类成员概率估计(来自方法predict_proba和predict_log_proba)。在二分类情况下,使用Platt缩放对概率进行校准:对SVM分数进行逻辑回归,通过对训练数据的额外交叉验证进行拟合。在多类情况下,这被扩展为Wu等人(2004年)所述的方式。
不用说,Platt缩放中涉及的交叉验证对于大型数据集来说是一项昂贵的操作。此外,概率估计可能与分数不一致,即分数的“argmax”可能不是概率的argmax。(例如,在二元分类中,根据predict_proba预测,样本可能被标记为属于概率小于½的类。)Platt的方法也被认为存在理论问题。如果需要置信度分数,但这些分数不必是概率,则建议将probability设置为False,并使用decision_function而不是predict_proba。
这个功能在 Stack Overflow 的用户中也存在很多困惑,你可以在 这个帖子 或者 这个帖子 中看到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接