之前在做learning from data支持向量机一章习题的时候,需要计算SVM的一些参数,例如超平面的方程,截距等等,
这里简单总结一下。

我们知道,SVM算法最后是求解如下二次规划问题

其中$z_n=\phi(x_n)$

这里我把问题统一起来,如果是Hard Margin,那么取$\xi_n=0$即可,如果没有没有特征转换,那么$z_n=x_n$。
现在的问题是通过sklearn求解$w,b$,下面分别介绍原始数据以及进行特征转换的情形下如何求解这两个参数。

原始数据

import numpy as np
import matplotlib.pyplot as plt

N = 20
x1 = np.random.uniform(0, 1, N)
x2 = np.random.uniform(-1, 1, N)
x = []
for i in range(N):
    x.append([x1[i], x2[i]])
x = np.array(x)
y = np.sign(x2)

plt.scatter(x1[y>0], x2[y>0], label="+")
plt.scatter(x1[y<0], x2[y<0], label="-")
plt.legend()
plt.show()

png

这里没有进行特征转换,直接使用kernel =’linear’即可,下面使用SVM算法进行计算。

from sklearn import svm
clf=svm.SVC(kernel ='linear',C=1e10)
clf.fit(x,y)

#获得超平面
w = clf.coef_[0]
b = clf.intercept_[0]

#作图
xx = np.array([-1,1])
yy = -(b+w[0]*xx)/w[1]
plt.scatter(x1[y>0], x2[y>0],label="+")
plt.scatter(x1[y<0], x2[y<0],label="-")
plt.plot(xx,yy,'r')
plt.legend()
plt.show()

png

这里主要用了以下两个式子。

w = clf.coef_[0]
b = clf.intercept_[0]

可以看到,如果不进行特征转换,求起来还是很方便的,下面介绍进行特征转换之后的求解方式。

特征转换

接下来计算多项式特征转换之后的参数。

clf = svm.SVC(kernel='poly', degree=2, coef0=1, gamma=1, C=1e10)
clf.fit(x, y)

#特征转换的函数
def g(x):
    r = np.sqrt(2)
    return np.array([1,r*x[0],r*x[1],x[0]**2,x[0]*x[1],x[1]*x[0],x[1]**2])
#获得特征转换之后的向量
z = np.array([g(i) for i in x])

#支持向量的索引
index = clf.support_
#获得系数
coef = clf.dual_coef_[0]

#取第一个支持向量
i = index[0]

#计算
b = y[i] - coef.dot(z[index].dot(z[i]))
w = (coef).dot(z[index])

b,w
(-0.35853516196992885,
 array([ -3.55271368e-15,   1.35696537e+00,   4.08371930e+00,
          2.06504400e-01,   1.10631880e+00,   1.10631880e+00,
         -3.45712814e-01]))

解释代码之前,先验证一下这个式子的合理性,因为最后的结果和取哪个特征向量无关,所以对这里的i取别的值看看。

#取第一个支持向量
i = index[1]

#计算
b = y[i] - coef.dot(z[index].dot(z[i]))
w = (coef).dot(z[index])

b,w
(-0.35906757282313428,
 array([ -3.55271368e-15,   1.35696537e+00,   4.08371930e+00,
          2.06504400e-01,   1.10631880e+00,   1.10631880e+00,
         -3.45712814e-01]))

可以看到,和之前的结果一致,下面解释下代码。

回顾下$w,b$的计算公式。

可以看到,我们计算时需要的是$z_n$,我这里取的核函数为

如果$x=(x_1,x_2)$,那么对应的特征转换为

这也就是之前代码中

#特征转换的函数
def g(x):
    r = np.sqrt(2)
    return np.array([1,r*x[0],r*x[1],x[0]**2,x[0]*x[1],x[1]*x[0],x[1]**2])
#获得特征转换之后的向量
z = np.array([g(i) for i in x])

这两句的作用。

接下来比较关键的是找到支持向量以及计算出$w=\sum_{n=1}^Ny_n\alpha_nz_n$中的系数$y_n,\alpha_n$。我们看到$w$的计算式子,实际上我们只需要考虑支持向量即可,因为非支持向量对应的$\alpha_n=0$,现在来看下代码。

#支持向量的索引
index = clf.support_
#获得系数
coef = clf.dual_coef_[0]

$\text {clf.support_}$的意义是获得对应特征向量的索引,$\text{coef = clf.dual_coef_[0]}$获得的是支持向量对应的$\alpha_ny_n$。有了以上几点,就可以计算$w,b$。

#取第一个支持向量
i = index[0]

#计算
b = y[i] - coef.dot(z[index].dot(z[i]))
w = (coef).dot(z[index])