绪论
支持向量机(SVM)以一个可怕的名字出现在人们面前,暗示着某种复杂或可怕的东西可能正在发挥作用。在这里,我们将使用Scikit-Learn从实用的角度,而不是理论的角度来看待SVM。
正如我们将看到的,与逻辑回归相比,SVM通常被用作一种更准确的分类手段。
输入和模板
1import numpy as np
2import pandas as pd
3import matplotlib.pyplot as plt
4from sklearn.model_selection import train_test_split
5from sklearn.preprocessing import MinMaxScaler
6from sklearn.linear_model import LinearRegression
7from sklearn.linear_model import LogisticRegression
8from sklearn.svm import SVC
9
10plt.rcParams['figure.figsize'] = [8, 7]
11plt.rcParams['figure.dpi'] = 100
一个分类问题:红点与蓝点。
我们使用分类法来预测一个类别与另一个类别的可能性,给定一个或多个特征。
让我们考虑一下由红点和蓝点组成的两个类别(即二元/二项式分类)。不要太在意下面的代码,直接跳到图上,我们再继续讨论。
1np.random.seed(0)
2samples = 80
3red_x = np.linspace(1,8,samples)
4red_y = [ v + 0.5 + np.random.rand()*(10-v-2) for v in red_x]
5
6blue_x = np.linspace(1,10,samples)
7blue_y = [ v-(np.random.rand()*v) for v in blue_x]
8
9X = np.concatenate((
10 np.array( [ [x,y] for (x,y) in zip(red_x,red_y)]),
11 np.array( [ [x,y] for (x,y) in zip(blue_x,blue_y)])
12 ))
13y = np.concatenate((
14 np.repeat(0,len(red_x)),
15 np.repeat(1,len(blue_x))
16 ))
17
18def visualise(models,names):
19 plt.scatter(red_x,red_y, color='red')
20 plt.scatter(blue_x,blue_y, color='blue')
21 plt.xticks(range(0,11))
22 plt.yticks(range(0,11))
23 plt.xlabel("X")
24 plt.ylabel("Y")
25 for i,m in enumerate(models):
26 class_boundary = [ (x,y)
27 for x in np.linspace(0,10,200)
28 for y in np.linspace(0,10,200)
29 if abs((m.predict_proba([[x,y]])[0][1])-0.5)
30 <= 0.001 ]
31 plt.plot([ t[0] for t in class_boundary ],
32 [ t[1] for t in class_boundary ],
33 label=names[i])
34 if len(models) > 0:
35 plt.legend(loc='upper left')
36
37
38visualise([],[])
好的,上面我们有X轴和Y轴(都在0...10范围内),根据坐标的不同,我们更有可能得到红点或蓝点。
Logistic 回归
我们可以使用的一个简单的预测模型是逻辑回归(查看我的教程),它将预测(排除正则化等因素)红点或蓝点,取决于它们是在茶色决策边界线之上还是之下。
1model_logistic = LogisticRegression()
2model_logistic.fit(X,y)
3visualise([model_logistic],["Logistic"])
正如你在上面看到的,逻辑回归模型已经做得很好了。通常情况下,你不需要一个比这更复杂的模型。
但是,有一点不太对劲....,直觉上,你知道你可以自己画出决策边界线,而不重叠或接触任何点,对吗?
进入支持向量机!
支持向量机(SVM)
好吧,支持向量机中的支持向量,通俗地说,就是那些更接近任何一类的线,而不接触任何点!我们来看看。让我们来看看。
1model_svm = SVC(kernel = 'linear',probability=True)
2model_svm.fit(X,y)
3visualise([model_logistic,model_svm],["Logistic","Linear SVM"])
现在你可以看到这两者之间的区别了。SVM模型建议的决策边界完全位于两个点簇之间,没有接触或与任何一个点重叠。
让我们不要急于下结论说SVM一定比简单的逻辑模型 "优越"。
目的
当重要的不是每个类中的特征的总影响时,SVM模型是合适的。相反,在SVM中,目标是将决策边界定义为离最接近的点越远越好--以视觉化的方式。
这种 "远离小点 "的事情就是天网背后的统计学家所说的边际,如图中可爱的T-800所示。
边际是--还是那句话,用通俗的话说--"上面 "的支持向量和 "下面 "的支持向量之间的宽度。
如果这仍然过于神秘,你可以想象在逻辑回归中,所有的点都对决策边界线施加了引力,而在SVM中,只有在边缘的点与决策边界线有关。
正则化
像大多数其他模型一样,SVM可以使用C 参数进行正则化。该值越低,模型就越有偏向性。通俗地说,在两边有更多的点的情况下,它变得越不 "听话"。该值越低,偏差越大。
1model_svm2 = SVC(kernel = 'linear',probability=True, C=0.01)
2model_svm2.fit(X,y)
3visualise([model_logistic,model_svm,model_svm2],
4 ["Logistic","SVM", "SVM with regularisation"])
请注意,对于我们的数据集,没有正则化的SVM模型已经足够了。突出的绿线是故意的。
非线性模型和核
你可能听说过核化支持向量机。Linus Torvalds和SVM有什么关系?没有。因为在SVM中已经有了足够多的隐秘的词了!放松点,数学界人士喜欢迷惑凡人!
还记得多项式回归吗(见我之前的博文),当你有一条曲线时,你仍然可以使用线性回归(以多项式回归的形式),在这种情况下,你保持相同的模型,只是变换特征。
好吧,不改变模型本身,而是对特征进行修补的一般方法,在它们被送入基础模型之前,被称为内核。
这些经过改造的特征导致了机器学习专家所说的 "高维空间"。这让我想起了这个。
现在,好消息是,内核的实现完全被封装在Scikit-Learn中,所以我们不需要真的去修补所有这些阴暗地带的事情。
让我们废话少说,看一个例子,由绿色和紫色的小点组成,作为一个改变。像往常一样,不要担心下面的代码,只要跳到情节。
1np.random.seed(1)
2samples = 200
3
4dataset = np.array([ (x,2+(np.random.rand()*2),
5 1 if 5.5 > x > 4 else 0 )
6 for x in np.linspace(0,8,samples) ])
7
8green_x = [ x for (x,y,v) in dataset if not v ]
9green_y = [ y for (x,y,v) in dataset if not v ]
10purple_x = [ x for (x,y,v) in dataset if v ]
11purple_y = [ y for (x,y,v) in dataset if v ]
12
13X = np.array([ [x,y] for (x,y,_) in dataset ])
14y = np.array([ z for (_,_,z) in dataset ])
15
16def visualise(models,names):
17 plt.scatter(green_x, green_y, color='green')
18 plt.scatter(purple_x, purple_y, color='purple')
19 plt.yticks([0,2,4,6])
20 plt.xticks([0,2,4,6,8])
21 plt.xlabel("X")
22 plt.ylabel("Y")
23 for i,m in enumerate(models):
24 class_boundary = [ (x,y)
25 for x in np.linspace(0,10,200)
26 for y in np.linspace(0,70,200)
27 if abs((m.predict_proba([[x,y]])[0][1])-0.5)
28 <= 0.01 ]
29 plt.plot([ t[0] for t in class_boundary ],
30 [ t[1] for t in class_boundary ],
31 label=names[i])
32 if len(models) > 0:
33 plt.legend(loc='upper left')
34
35visualise([],[])
事情当然变得更加有趣。与刚才看到的红点和蓝点不同,上面的绿点和紫点并不都是快乐地生活在自己的社区里。我们有绿色的,然后是紫色的,然后又是绿色的。
在这个特殊的例子中,我们尝试使用径向基函数(RFB)内核,没有任何额外的超参数、正则化等。
1np.random.seed(1)
2
3model_svm = SVC(kernel = 'rbf',probability=True,gamma='auto')
4model_svm.fit(X,y)
5
6visualise([model_svm],["SVM RBF"])
7display(model_svm.score(X,y))
0.985
我们不会深入研究RBF的基础数学,但只需说它对表现出某种高斯分布的数据集有帮助。在上面的例子中,我们可以看到RBF是如何实现将中间的紫色小点和绿色小点分开的模型。
总结
我们看到了支持向量机(SVM)的实际应用。当用于分类时,与传统的逻辑回归相比,SVM的关键优势在于它关注类之间的距离(margin),而不是像使用最小二乘法那样关注每个数据点的影响。
我们展示了线性核的有用性,以及一个以RBF形式出现的更高级核的例子。Scikit-Learn还支持其他内核,如 "poly"、"sigmoid "和 "precomputed"。这些可能是未来文章的主题。