使用 SVM 预测概率

Posted

技术标签:

【中文标题】使用 SVM 预测概率【英文标题】:Predict probabilities using SVM 【发布时间】:2018-09-05 12:27:24 【问题描述】:

我写了这段代码,想得到分类的概率。

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 类。 【参考方案1】:

编辑:正如@TimH 所指出的,概率可以由clf.decision_function(X) 给出。下面的代码是固定的。注意到使用predict_proba(X) 的低概率指定问题,我认为答案是根据官方文档here,....此外,它会在非常小的数据集上产生毫无意义的结果。

理解 SVM 的结果概率是多少的答案。 简而言之,您在 2D 平面上有 7 个类和 7 个点。 SVM 试图做的是在每个类和其他类之间找到一个线性分隔符(一对一的方法)。每次只选择2个班级。 您得到的是归一化后分类器的投票。在this 帖子或here(scikit-learn 使用 libsvm)中查看关于 libsvm 的多类 SVM 的更多详细说明。

通过稍微修改您的代码,我们看到确实选择了正确的类:

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')

【讨论】:

我认为他的主要问题是理解为什么正确类别的概率是最小的。这个问题不在这里回答 @PKlumpp 谢谢,添加了关于概率的注释。 @mr_mo 您使用什么工具/IDE 来获取绘图..?我试图在 Ubuntu 终端上运行代码......它给了我预测但没有图表 我使用了matplotlib.pyplot。示例自成体系,代码如下。 @VidyaMarathe 我在 Jupyter 中使用过,只需添加 plt.show() 即可查看图表。【参考方案2】:

您应该禁用probability 并改用decision_function,因为不能保证predict_probapredict 返回相同的结果。 您可以在documentation 中阅读更多相关信息。

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 

【讨论】:

您的答案没有花哨的情节,但对我来说是最有用的一个,我只想补充一点,您可以将 softmax 应用于 decision_function 的输出,以将其转换为概率,这就是用户要求添加开头 @Kailegh 感谢您的反馈。我将不胜感激。 upps,对不起,给你! =D【参考方案3】:

你可以read in the docs那个...

SVC 方法 decision_function 为每个样本提供每个类别的分数(或在二元情况下每个样本的单个分数)。当构造函数选项概率设置为 True 时,将启用类成员概率估计(来自方法 predict_proba 和 predict_log_proba)。在二进制情况下,概率使用 Platt 标度进行校准:SVM 分数的逻辑回归,通过对训练数据的额外交叉验证进行拟合。在多类情况下,这根据 Wu 等人进行了扩展。 (2004 年)。

不用说,Platt 缩放所涉及的交叉验证对于大型数据集来说是一项昂贵的操作此外,概率估计可能与分数不一致,从某种意义上说,分数的“argmax”可能不是概率的argmax。 (例如,在二元分类中,一个样本可能会被 predict 标记为属于概率 的类别。)Platt 的方法也存在理论问题。 如果需要置信度分数,但不一定是概率,则建议设置probability=False 并使用decision_function 而不是predict_proba。

Stack Overflow 用户对此功能也有很多困惑,您可以在 this thread 或 this one 中看到。

【讨论】:

以上是关于使用 SVM 预测概率的主要内容,如果未能解决你的问题,请参考以下文章

使用 scikit-learn SVM 将预测标记为概率分数预测/AUC

SkLearn SVM - 如何获得按概率排序的多个预测?

SVM 模型将概率分数大于 0.1(默认阈值 0.5)的实例预测为正例

如何使用 libsvm 计算多类预测的概率?

SVM LibSVM 在预测时忽略特征 1,3,5

如何计算小数据集的 SVM 分类概率(置信度)?