在我最近的帖子中,我向你展示了如何为二进制分类问题解释拟合SVC模型的coef和intercept_属性,以及如何绘制决策平面。如果你还没有读过,我建议你在读这篇文章之前先看看。下面是它的链接:
https://towardsdatascience.com/understanding-the-hyperplane-of-scikit-learns-svc-model-f8515a109222
注意:因为前一篇文章围绕着一个二分类问题,所以它基本上是我们使用的SVM。
在这篇文章中,我们实际上使用了SVC,我们将利用SVC的功能。SVM和SVC的主要区别在于,SVC本质上只是多个SVM的组合,因此允许我们使用多个超平面对多个类进行分类。
本文的主题有点复杂,但我会尽我所能使它易于理解。
创建一些虚拟数据
首先,让我们创建一些数据来使用和可视化。
下面的代码段可以做到这一点:
import numpy as np
import matplotlib.pyplot as plt
X = np.array([
[1.5, 1 ], [1.5, 2 ], [ 2, 1 ], [ 2, 2 ], #upper right (Green)
[1, -1 ], [1, -2 ], [ 2, -1 ], [ 2, -2 ], #lower right (Blue)
[-1, -1.5], [-1, -2.5], [-2, -1.5], [-2, -2.5], #lower left (Red)
[-1, 1 ], [-1, 2 ], [-2, 1 ], [-2, 2 ], #upper left (Yellow)
])
y = np.array([
'green','green','green','green',
'blue','blue','blue','blue',
'red','red','red','red',
'yellow','yellow','yellow','yellow',
])
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
这应产生以下曲线:
正如你所见,这些数据显然是线性可分离的,所以线性SVC应该能很好地处理它,而且因为有两个以上的类,我们将需要一个以上的超平面,(直觉应该很容易理解。想象一下,必须画一条直线来分隔四个不同的类。你根本无法做到)。
在数据上拟合SVC
下一步是使用scikit-learn的库在我们的数据上拟合。这可以简单地这样做:
from sklearn.svm import SVC
clf = SVC(kernel='linear')
clf.fit(X, y)
就SVC而言,存在两种创建超平面的方法。一种叫做一对一(OVO),另一种叫做一对剩余(OVR)。我现在将不再详细讨论这个问题,因为这是另一篇文章的主题。
现在,你只需要知道我们将创建一个OVO SVC。简言之,这意味着我们将把每个类与其他类进行比较,并且每个比较都会有一个对应的超平面。
我们可以查看拟合的SVC的coef和intercept_属性,就像我们在上一篇文章中所做的那样。
print('coef_\n', clf.coef_)
print('intercept_', clf.intercept_)
>> coef_
[[ 0.00000000e+00 -1.00000000e+00]
[ 9.99532404e-01 2.22044605e-16]
[ 5.00000000e-01 -5.00000000e-01]
[ 4.00000000e-01 4.00000000e-01]
[ 8.00000000e-01 0.00000000e+00]
[ 0.00000000e+00 -8.00000000e-01]]
>> intercept_
[ 1.45716772e-16
4.30211422e-16
0.00000000e+00
0.00000000e+00
-2.00000000e-01
-2.00000000e-01]
好吧,显然我们得到了6个coef属性的向量和6个intercept_属性的值。这些是我们将用来绘制超平面的值,也用于对新数据点进行分类。
为什么你会问数字6?为了回答这个问题,让我们看看SVC的scikit学习文档:
我们现在可以看到,值6来自以下等式:
在我们的例子中,我们有4个类,因此等式如下:
希望这一点现在已经清楚了。然而,这给我们留下了一个后续问题:哪个coef_vector和intercept_value对应于哪个标签?如上所述,OVO方法将每个类相互比较。这意味着我们比较
标签1对标签2
标签1对标签3
标签1对标签4
标签2对标签3
以此类推……直到所有标签相互比较,(我将在后面的文章中进一步详细介绍如何对新数据点进行分类)
我们的每一个coef_向量都表示这样的比较。但是,我们如何知道哪个向量对应于哪个比较。
为了解决这个问题,我们可以使用以下代码来获得数据和超平面的可视化表示:
line_colors = {0:'red', 1:'blue', 2:'green', 3:'yellow', 4:'black', 5:'gray'}
number_of_coefficients = len(clf.coef_)
figure, axis = plt.subplots(3, 2)
row = 0
col = 0
for j in range(number_of_coefficients):
for i in range(j+1):
w = clf.coef_[i]
w = [w[0], w[1] + 0.0001] #adding 0.0001 just to make sure we
#don't devide by 0
a = -w[0] / w[1]
xx = np.linspace(-4,4)
yy = a * xx - clf.intercept_[i] / w[1]
axis[row, col].plot(xx, yy, label=f'h{i}', c=line_colors[i])
axis[row, col].set_xlim([-4, 4])
axis[row, col].set_ylim([-4, 4])
axis[row, col].scatter(X[:, 0], X[:, 1], c = y)
row = row + 1 if col == 1 else row
col = col + 1 if col != 1 else 0
plt.show()
(为了避免文章太长,我没有对代码片段进行解释,请注意,它用于使用coef_和intercept_值创建绘图)
这将生成以下绘图:
这里发生了很多事情,所以让我们仔细看看。
每个子图都会添加一个额外的超平面。这样,我们可以通过检查刚刚添加的超平面的位置,了解哪些超平面对应于哪个比较。以下是超平面的描述:
- 红线将蓝色类与绿色类进行比较。
- 蓝线将蓝色类与红色类进行比较。
- 绿线将蓝色类与黄色类进行比较。
- 黄线将绿色类与红色类进行比较。
- 黑线将绿色类与黄色类进行比较。
- 灰色线将红色类与黄色类进行比较。
当对新数据点进行分类时,将针对每个超平面测量该点。每次比较后,我们都会注意到它被归类为哪个标签,并将其添加到该标签的累积分数中。最后,新的数据点被简单地标记为得分最高的类。
每个超平面按以下方式对新数据点进行分类:如果该点位于超平面的右侧,则该超平面将该点分类为其比较中的第一个标签。相反,如果点在平面的左侧,则它被标记为超平面比较的第二类。
快速示例:以红线为例,它的第一个标签是蓝色类,第二个标签是绿色类。如果给定的数据指向直线的右侧,则此超平面将其分类为蓝色。
注:为了获得超平面的“右”或“左”,它们需要有一个方向。在这种情况下,红色和灰色线指向右侧,蓝色和黑色线指向上方,黄色线指向左侧,绿色线指向右侧。
新点示例
让我们看一个例子。我们可以画出一个新的点[1.5,-2.5](图中的棕色点),我们预计它将被归类为蓝色点。下面是一个使其更明显的图:
逐个比较(超平面):
- 红线将其归类为蓝色
- 蓝线将其归类为蓝色
- 绿线将其归类为蓝色
- 黄线将其归类为红色
- 黑线将其归类为绿色
- 灰色线条将其归类为红色
新点分为蓝色3次、红色2次和绿色1次。因此,我们用蓝色标签对点进行分类。
如果我们使用拟合模型进行预测,我们应该得到相同的结果。可以通过以下方式完成:
new_point = np.array([[1.5, -2.5]])
print(clf.predict(new_point))
>> ['blue']
我们得到了预期的蓝色标签。
如何确定比较顺序
我希望上面的例子对你来说很容易理解,并且你理解我们是如何得出结论的,关于哪些超平面对应于哪些比较。
然而,这是一个简单的实验,数据很容易分离。这使得我们能够通过目视检查来确定超平面和coef_属性之间的关系。然而,现实世界的数据很可能不那么容易处理。因此,你可能会想,是否有一个系统来确定比较的顺序?
换句话说,我们能确定由coef_[0]表示的超平面总是将蓝色类与绿色类分开的超平面吗?
我得出的结论是,排序是通过对标签进行排序来确定的。
在这个标签是单词的情况下,我注意到前三个超平面coef_[0]、coef_[1]和coef_[2]都与蓝色标签有关。这支持了我的理论,因为蓝色词典(按字母顺序)将作为第一个标签排序。以下两个标签coef_[3]和coef_[4]涉及绿色标签,因为“g”在“b”之后、“r”之前和“y”之前排序。
这可能有点棘手,但仔细想想,这对你来说很有意义。
有了这些关于模型超平面如何工作的信息,你将更好地了解幕后发生的事情。你还可以使用文章中的代码片段绘制超平面。
感谢阅读!