前面几篇博文都很理论,没有实例,更没有代码,不太像我的风格,那么接下来就直接来解决一个问题.$ $

问题

soft_svm_png
显然利用hard-margin svm使可以把它们分开的.但是这不是我们想要的结果,因为最左边那个蓝色的点是一个outlier.因此就有了今天的soft-margin svm

理论

我们把原来的优化问题加入一些新的惩罚项,如下:

\[ \mathop{}_{w,b}^{\min}\qquad \frac{1}{2}||w||^{2}+C\sum_{i=0}^{m}\xi _{i}\\\\ \begin{align} s.t.\qquad y^{(i)}(w^{T}x^{(i)}+b)\geq 1-\xi_{i},\qquad &i=1,2,\ldots,m\\\\ \xi_{i}\geq 0,\qquad &i=1,2,\ldots,m \end{align} \]

首先,上面的式子能达到不需要数据完全分开的效果.其次,\(\xi\)表示点与1的margin(距离)大小,\(\xi\)小于1表示在margin和hyperplane之间,大于1,则跑到hyperplane的另一端,即分错了

C越大,对错误的容忍度就越小,margin越小
C越小,对错误容忍度就越高,margin越大

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# encoding=utf8
import numpy as np
from sklearn.svm import SVC
import matplotlib.pyplot as plt
def load_data():
"""加载原始数据,以及特征数据构建和组合
  h=theta0*1+theta1*x+theta2*x^2+theta3*y+theta4*y^2
Returns:
xy:ndarray类型,(num_samples*2);被分类的点的坐标
lable:ndarray类型,(num_samples,);被分类的点的标签
"""
class_data=np.loadtxt('./data/twofeature.txt')
# 点的xy坐标
xy=class_data[:,1:]
# 标签数据
lable=class_data[:,0:1]
lable=lable.reshape(lable.shape[0],)
return xy,lable
def plot(xy,lable,w,b,sv):
"""画出分类的数据,支持向量以及分类直线
注意:无论形状,同一颜色为同一类;其中五角星形状的为该分类的支持向量
Args:
xy:ndarray类型,(num_samples*2);被分类的点的坐标
lable:ndarray类型,(num_samples,);被分类的点的标签(1或-1)
w:ndarray类型,(1*2);学习到的参数
b:ndarray类型,(1*1);截距
sv:ndarray类型,(num_sv*2);支持向量
"""
num=xy.shape[0]
for i in xrange(num):
if int(lable[i]) == -1:
# 判断是否为支持向量
if xy[i].tolist() in sv.tolist():
# 用符号和大小显著表明支持向量
plt.plot(xy[i, 0], xy[i, 1], 'r*',markersize=10)
else:
plt.plot(xy[i, 0], xy[i, 1], 'ro')
elif int(lable[i]) == 1:
if xy[i].tolist() in sv.tolist():
plt.plot(xy[i, 0], xy[i, 1], 'b*',markersize=10)
else:
plt.plot(xy[i, 0], xy[i, 1], 'bo')
# 画分类直线
x = np.linspace(0, 4.)
y = np.linspace(1.5, 5.)[:, None]
plt.contour(x, y.ravel(), w[0,0]*x+w[0,1]*y+b, [0],colors='y')
# 坐标轴等比例显示
plt.axis('equal')
plt.show()
if __name__ == '__main__':
# 加载数据
X,y=load_data()
# 使用scikit-learn SVC(surppot vector classfication)库进行SVM分类
clf=SVC(C=1,kernel='linear')
clf.fit(X,y)
# 获得参数w,该方法限制linear模型
w=clf.coef_
# 这个适用更加广阔
# w=np.dot(clf.dual_coef_,clf.support_vectors_)
# 截距
b=clf.intercept_
sv=clf.support_vectors_
# print np.dot(sv,w.T)+b
# print sv
# 画图
plot(X,y,w,b,sv)

代码运行结果(注:相同颜色为同一类,五角星为support vector):

C=1

C=100

推荐:

SVM Linear Classification
Soft-Margin Support Vector Machine