一个非常基本的示例中的 SVM-OVO 与 SVM-OVA

Posted

技术标签:

【中文标题】一个非常基本的示例中的 SVM-OVO 与 SVM-OVA【英文标题】:SVM-OVO vs SVM-OVA in a very basic example 【发布时间】:2021-03-07 14:46:01 【问题描述】:

为了了解 SVM-OVR (One-Vs-Rest) 的工作原理,我正在测试以下代码:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
x = np.array([[1,1.1],[1,2],[2,1]])
y = np.array([0,100,250])
classifier = SVC(kernel='linear', decision_function_shape='ovr')
classifier.fit(x,y)
print(classifier.predict([[1,2]]))
print(classifier.decision_function([[1,2]]))

输出是:

[100]
[[ 1.05322128  2.1947332  -0.20488118]]

这意味着样本[1,2]100类中被正确预测(这很明显,因为[1,2]也用于训练)。

但是,让我们来看看决策函数。 SVM-OVA 应该生成三个分类器,即三行。第一个将class1class2 U class3 分开,第二个将class2class1 U class3 分开,第三个将class3class1 U class2 分开。我最初的目标是准确理解决策函数值的含义。我知道正值意味着样本在平面的右侧,反之亦然;值越大,样本与超平面之间的距离(本例中为直线)越大,样本属于该类的置信度越大。

但是,由于两个决策函数值是正的,因此显然有些错误,而假设只有正确的类应该报告正的决策函数(因为预测值也是训练样本)。为此,我尝试绘制分隔线。

fig, ax = plt.subplots()
ax.scatter(x[:, 0], x[:, 1], c=y, cmap=plt.cm.winter, s=25)
# create a mesh to plot in
x_min, x_max = x[:, 0].min() - 1, x[:, 0].max() + 1
y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
xx2, yy2 = np.meshgrid(np.arange(x_min, x_max, .2),np.arange(y_min, y_max, .2))
Z = classifier.predict(np.c_[xx2.ravel(), yy2.ravel()])
Z = Z.reshape(xx2.shape)
ax.contourf(xx2, yy2, Z, cmap=plt.cm.winter, alpha=0.3)

w = classifier.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[0]) / w[1]
ax.plot(xx,yy)

w = classifier.coef_[1]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[1]) / w[1]
ax.plot(xx,yy)

w = classifier.coef_[2]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (classifier.intercept_[2]) / w[1]
ax.plot(xx,yy)

ax.axis([x_min, x_max,y_min, y_max])
plt.show()

这是我得到的:

惊喜:确实,当计算 OVO(One-Vs-One)策略时,这些分隔线代表超平面:确实,您可以注意到这些线将 class1class2 分开,class2 与 @987654338 分开@ 和 class1 来自 class3

我也尝试添加一个类:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.svm import SVC
x = np.array([[1,1.1],[1,2],[2,1],[3,3]])
y = np.array([0,100,250, 500])
classifier = SVC(kernel='linear', decision_function_shape='ovr')
classifier.fit(x,y)

然后发生的是表示决策函数的向量的长度等于 4(根据 OVA 策略),但又生成了 6 行(好像我已经实现了 OVO 策略)。

classifier.decision_function([[1,2]])
[[ 2.14182753  3.23543808  0.83375105 -0.22753309]]

classifier.coef_
array([[ 0.        , -0.9       ],
   [-1.        ,  0.1       ],
   [-0.52562421, -0.49934299],
   [-1.        ,  1.        ],
   [-0.8       , -0.4       ],
   [-0.4       , -0.8       ]])

我的最后一个问题:决策函数值代表什么?为什么即使应用 OVA 策略,也会生成n(n-1)/2 超平面,而不是n 超平面?

【问题讨论】:

【参考方案1】:

关键是,默认情况下,SVM 确实实现了 OvO 策略(请参阅 here 以供参考)。

SVC 和 NuSVC 实现了多类分类的“一对一”方法。

同时,默认情况下(即使您已明确表示)decision_function_shape 设置为 'ovr'

“为了提供与其他分类器的一致接口,decision_function_shape 选项允许将“one-vs-one”分类器的结果单调转换为形状的“one-vs-rest”决策函数(n_samples,n_classes) .

实施 OvO 策略的原因是 SVM 算法无法根据训练集的大小进行扩展(并且使用 OvO 策略,每个分类器仅在训练集对应于它必须的类的部分上进行训练)区分)。 原则上,您可以通过OneVsRestClassifier 的实例强制SVM 分类器实现OvA 策略,例如:

ovr_svc = OneVsRestClassifier(SVC(kernel='linear'))

【讨论】:

是的,完全正确。这就是行为。 老实说,我从未详细了解过它。这可能是正确的场合:) 目前,我可以报告以下link。特别是,“如果 decision_function_shape='ovo',则函数值与样本 X 到分离超平面的距离成正比。...如果 decision_function_shape='ovr',则决策函数是 ovo 决策函数的单调变换。 " 最终,以下是 sklearn 实现的相关来源:decision_function method implementation within BaseSVC class 和 _ovr_decision_function implementation。 根据发布的链接,使用的单调变换为 f: x -> x / (3 * (|x| + 1)) 好的,谢谢,但最后一个方程并没有减少形状。这很奇怪。

以上是关于一个非常基本的示例中的 SVM-OVO 与 SVM-OVA的主要内容,如果未能解决你的问题,请参考以下文章

e1071 的基本 SVM 问题:测试错误率与 tune 的结果不匹配

sklearn svm 不合适

Encog中的多类SVM分类

SVM-支持向量机线性SVM分类

SVM原理推导核SVM为什么能分类非线性问题?

支持向量机SVM