三、SVM基础

SVM理论学习

支持向量机(SVM)是一类经典的机器学习算法,给定训练集D={(x1,y1),(x2,y2),…,(xn,yn)},yi∈{-1,1},支持向量机试图找到一个平面把样本给分隔开,这个平面叫划分超平面wTx+b = 0的划分超平面。样本点xi到超平面wTx+b=0的距离为r(xi),距离超平面最近的几个训练样本点称为支持向量,两个不同类别的支持向量到超平面的距离之和r = 2/||w||称为间隔

假设我们得到了一个划分超平面wTx+b = 0,那么:
w T x i + b ≤ − 1 , y i = − 1 w T x i + b ≥ − 1 , y i = + 1 w^Tx_i +b \le -1,y_i = -1 \\ w^Tx_i +b \ge -1,y_i = +1 wTxi+b1,yi=1wTxi+b1,yi=+1
则求解最大间隔划分超平面对应于优化问题:
min ⁡ w , b 1 2 ∣ ∣ w ∣ ∣ 2 s . t . y i ( w T x i + b ) ≥ 1     ( i ∈ [ m ] ) \min_{w,b} \frac{1}{2} ||w||^2 \\ s.t . y_i(w^Tx_i +b)\ge1 \ \ \ (i∈[m]) w,bmin21w2s.t.yi(wTxi+b)1   (i[m])
通过这个问题我们可以得到一个拉格朗日函数(不懂的请看我之前的博客)
L ( w , b , α ) = 1 2 ∣ ∣ w ∣ ∣ 2 + ∑ i = 1 m a i ( 1 − y i ( w T x i + b ) )     ( i ∈ [ m ] ) L(w,b,α) = \frac{1}{2}||w||^2+\sum_{i=1}^m a_i(1-y_i(w^Tx_i +b))\ \ \ (i∈[m]) L(w,b,α)=21w2+i=1mai(1yi(wTxi+b))   (i[m])
其中拉格朗日乘子αi>=0,对函数未知量进行偏导等于0可得:
w = ∑ i = 1 m a i y i x i ∑ i = 1 m a i y i = 0 w = \sum_{i=1}^m a_iy_ix_i \\ \sum_{i=1}^m a_iy_i = 0 w=i=1maiyixii=1maiyi=0
把上面得到的三个式子联立,经过转化可以得到主问题的对偶问题:
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j − ∑ i = 1 m α i s . t .    ∑ i = 1 m α i y i = 0 ; α i ≥ 0 ( i ∈ [ m ] ) \min_{α} \frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m α_iα_jy_iy_jx_i^Tx_j -\sum_{i=1}^mα_i \\s.t. \ \ \sum_{i=1}^mα_iy_i = 0;α_i\ge0(i∈[m]) αmin21i=1mj=1mαiαjyiyjxiTxji=1mαis.t.  i=1mαiyi=0;αi0(i[m])
上述过程满足KKT条件:
∑ i = 1 m a i y i x i = w ; s u m i = 1 m α i y i = 0 ; α i ≥ 0 ; y i ( w T x i + b ) − 1 ≥ 0 ; a i ( 1 − y i ( w T x i + b ) ) = 0. \sum_{i=1}^m a_iy_ix_i = w; \\ sum_{i=1}^mα_iy_i = 0; \\ α_i\ge0; \\y_i(w^Tx_i +b) -1\ge0; \\a_i(1-y_i(w^Tx_i +b))=0. i=1maiyixi=w;sumi=1mαiyi=0;αi0;yi(wTxi+b)10;ai(1yi(wTxi+b))=0.
如果数据是分布在曲线两侧怎么办?
比如数据在y=x2上面跟下面用划分超平面无法简单划分在低维空间线性不可分,就把数据扩充到高维。

进行计算两多维变量距离的时候,有时候扩展到高维后使计算很困难,为此我们需要考虑核函数。
κ ( x i , x j ) = < ϕ ( x i ) , ϕ ( x j ) > = ϕ ( x i ) T ϕ ( x j ) \kappa(x_i,x_j) = <\phi(x_i),\phi(x_j)> = \phi(x_i)^T\phi(x_j) κxi,xj)=<ϕxi),ϕ(xj)>=ϕxi)Tϕ(xj)
xi跟xj在特征空间中的内积等于它们在原始样本空间中通过函数k(‘,’)计算的结果,这样就不必直接去计算高维甚至无穷维度特征中的内积,于是可以把公式改为:

min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j κ ( x i , x j ) − ∑ i = 1 m α i s . t .    ∑ i = 1 m α i y i = 0 α i ≥ 0 ( i ∈ [ m ] ) \min_{α} \frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m α_iα_jy_iy_j\kappa(x_i,x_j) -\sum_{i=1}^mα_i \\s.t. \ \ \sum_{i=1}^mα_iy_i = 0\\α_i\ge0(i∈[m]) αmin21i=1mj=1mαiαjyiyjκxi,xj)i=1mαis.t.  i=1mαiyi=0αi0(i[m])
核函数的定义:令X为输入空间,k(‘,’)是定义在X×X上的对称函数,则k是核函数当且仅当对于任意数据{x1,x2…xn},核矩阵K是一个半正定的m阶方阵,Kij=k(xi,xj

名称表达式参数
线性核 κ ( x i , x j ) = x i T x j \kappa(x_i,x_j) = x_i^Tx_j κxi,xj)=xiTxj
多项式核 κ ( x i , x j ) = ( x i T x j ) d \kappa(x_i,x_j) = (x_i^Tx_j)^d κxi,xj)=(xiTxj)dd>=1为多项式的次数
高斯核 κ ( x i , x j ) = e − ∥ x 1 − x 2 ∥ 2 2 σ 2 \kappa(x_i,x_j) = e^{ -\frac{\|x_1 - x_2\|^2} {2σ^2}} κxi,xj)=e2σ2x1x22σ>0且为高斯核的带宽
拉普拉斯核 κ ( x i , x j ) = e − ∥ x 1 − x 2 ∥ 2 σ 2 \kappa(x_i,x_j) = e^{ -\frac{\|x_1 - x_2\|} {2σ^2}} κxi,xj)=e2σ2x1x2σ>0
sigmoid核 κ ( x i , x j ) = t a n h ( β x i T x j + θ ) \kappa(x_i,x_j) = tanh(βx_i^Tx_j+\theta) κxi,xj)=tanh(βxiTxj+θ)tanh为双曲正切函数,β>0,θ<0

每个核函数都隐式定义了一个特征空间,称为再生核希尔伯特空间,核函数的选择会影响SVM的性能。
在现实的工作中很难让训练样本的特征空间线性可分,但是在现实工作中很难确定合适的核函数使得训练样本在特征空间中线性可分,可能是欠拟合或者过拟合造成的?
为此引入软间隔的概念,允许一小部分样本分类错误。在最大间隔的同时,让不满足约束的样本尽可能少,于是优化的目标函数可以写成:
m i n w , b   1 2 ∣ ∣ w ∣ ∣ 2 + β ∑ i = 1 m l 0 / 1 ( y i ( w T ϕ ( x i ) + b ) − 1 ) β > 0 l 0 / 1 ( x ) = I ( x < 0 ) min_{w,b} \ \frac{1}{2}||w||^2+β\sum_{i=1}^ml_{0/1}(y_i(w^T\phi(x_i)+b)-1)\\β>0\\l_{0/1}(x)=I(x<0) minw,b 21w2+βi=1ml0/1(yi(wTϕ(xi)+b)1)β>0l0/1(x)=I(x<0)
当β很大的时候,被迫使所有的样本全部满足,原先的定义,当β有限的时候,运行一部分样本不满足约束。
因为l0/1非凸不联系,因此我们用hinge损失作为替代l0/1,叫做替代损失
l h i n g e ( x ) = max ⁡ ( 0 , 1 − x ) l_{hinge(x)}=\max(0,1-x) lhinge(x)=max(0,1x)
优化目标函数的公式可以变为:
m i n w , b   1 2 ∣ ∣ w ∣ ∣ 2 + β ∑ i = 1 m max ⁡ ( 0 , 1 − y i ( w T ϕ ( x i ) + b ) ) β > 0 l 0 / 1 ( x ) = I ( x < 0 ) min_{w,b} \ \frac{1}{2}||w||^2+β\sum_{i=1}^m\max(0,1-y_i(w^T\phi(x_i)+b))\\β>0\\l_{0/1}(x)=I(x<0) minw,b 21w2+βi=1mmax(0,1yi(wTϕ(xi)+b))β>0l0/1(x)=I(x<0)
引入松弛变量ξi>=0,那么优化目标的公式可以变为:
m i n w , b   1 2 ∣ ∣ w ∣ ∣ 2 + β ∑ i = 1 m ξ i   s . t .    y i ( w T ϕ ( x i ) + b ) ≥ 1 − ξ i ξ i ≥ 0    ( i ∈ [ m ] ) min_{w,b} \ \frac{1}{2}||w||^2+β\sum_{i=1}^m\xi_i\\ \ s.t. \ \ y_i(w^T\phi(x_i)+b)\ge1-\xi_i \\ \xi_i\ge0 \ \ (i∈[m]) minw,b 21w2+βi=1mξi s.t.  yi(wTϕ(xi)+b)1ξiξi0  (i[m])
这个目标函数的相应的对偶问题为:
min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j κ ( x i , x j ) − ∑ i = 1 m α i s . t .    ∑ i = 1 m α i y i = 0 β ≥ α i ≥ 0 ( i ∈ [ m ] ) \min_{α} \frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m α_iα_jy_iy_j\kappa(x_i,x_j) -\sum_{i=1}^mα_i \\s.t. \ \ \sum_{i=1}^mα_iy_i = 0\\β\geα_i\ge0(i∈[m]) αmin21i=1mj=1mαiαjyiyjκxi,xj)i=1mαis.t.  i=1mαiyi=0βαi0(i[m])
最后总结SVM的优点与缺点
优点:

  • 在高维空间与大量数据的实战中效果依旧不错。
  • 在决策函数重使用训练集的子集,是高效利用内存的。
  • 不同的核函数可以得到不同的决策函数,对不同的问题都有较好的适应能力。

缺点:

  • 特征数量不要大于样本数量。
  • 支持向量机不直接提供概率估计,这些都是使用昂贵的五次交叉验算计算的。

代码:

1.用库实现

(1)分类问题

下面代码中我们用到了svc,在这里简单解释一下。
SVC(Support Vector Classification)就是支持向量机用于分类

'''
SVC参数解释
(1)C: 目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0;
(2)kernel:参数选择有RBF, Linear, Poly, Sigmoid, 默认的是"RBF";
(3)degree:if you choose 'Poly' in param 2, this is effective, degree决定了多项式的最高次幂;
(4)gamma:核函数的系数('Poly', 'RBF' and 'Sigmoid'), 默认是gamma = 1 / n_features;
(5)coef0:核函数中的独立项,'RBF' and 'Poly'有效;
(6)probablity: 可能性估计是否使用(true or false);
(7)shrinking:是否进行启发式;
(8)tol(default = 1e - 3): svm结束标准的精度;
(9)cache_size: 制定训练所需要的内存(以MB为单位);
(10)class_weight: 每个类所占据的权重,不同的类设置不同的惩罚参数C, 缺省的话自适应;
(11)verbose: 跟多线程有关,不大明白啥意思具体;
(12)max_iter: 最大迭代次数,default = 1, if max_iter = -1, no limited;
(13)decision_function_shape : ‘ovo’ 一对一, ‘ovr’ 多对多  or None 无, default=None
(14)random_state :用于概率估计的数据重排时的伪随机数生成器的种子。
 ps:7,8,9一般不考虑。
'''
from sklearn import svm
X = [[1,3], [-1,-3]]
Y = [0, 1]
clf = svm.SVC(gamma='scale')
clf.fit(X, Y) 
answer = clf.predict([[2, 2]])
print(clf.decision_function(X))#得到到分离超平面的距离

然后再说一下NuSVC(Nu-Support Vector Classification.)

'''
NuSVC参数
nu:训练误差的一个上界和支持向量的分数的下界。应在间隔(0,1 ]。
其余同SVC
'''
from sklearn import svm
X = [[0, 0], [2, 2],[0, 3],[4, 2]]
y = [0, 0, 1, 1]
clf = svm.NuSVC()
clf.fit(X, y)
print(clf.predict([[1, 1]]))

LinearSVC(Linear Support Vector Classification):这个没有关键词kernel,其实也类似于SVC。
与SVC的不同:

  • LinearSVC最小化squared hinge loss,而SVC最小化hinge loss
  • LinearSVC是基于liblinear实现的,会惩罚截距(penalize the intercept), SVC是基于libsvm实现的,不会惩罚截距。
  • liblinear库针对线性的模型进行了优化,因此在大量的数据上收敛速度会高于libsvm。
  • LinearSVC使用 (One-vs-All)方式来实现多分类问题,但SVC使用的是One-vs-One的方式来处理多分类的问题。
'''
LinearSVC 参数解释
C:目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0;
loss :指定损失函数
penalty :
dual :选择算法来解决对偶或原始优化问题。当n_samples > n_features 时dual=false。
tol :(default = 1e - 3): svm结束标准的精度;
multi_class:如果y输出类别包含多类,用来确定多类策略, ovr表示一对多,“crammer_singer”优化所有类别的一个共同的目标
如果选择“crammer_singer”,损失、惩罚和优化将会被被忽略。
fit_intercept :
intercept_scaling :
class_weight :对于每一个类别i设置惩罚系数C = class_weight[i]*C,如果不给出,权重自动调整为 n_samples / (n_classes * np.bincount(y))
verbose:跟多线程有关
'''
from sklearn import svm
from sklearn.datasets import load_iris #鸢尾花出来打工
X, y = load_iris(return_X_y=True)

clf1 = svm.LinearSVC().fit(X, y) #正常的
clf2 = svm.SVC(kernel='linear').fit(X, y) #核函数为linear的核函数
clf3 = svm.LinearSVC(loss='hinge').fit(X, y)
print("LinearSVC",clf1.score(X, y))
print("SVC(kernel='linear')",clf2.score(X, y))
print("LinearSVC(loss='hinge')",clf3.score(X, y))

(2)多分类问题

from sklearn import svm
X = [[0], [1], [2], [3]]
Y = [0, 1, 2, 3]
clf = svm.SVC(gamma='scale', decision_function_shape='ovo')
#ovo就是0分别跟1,2,3  1跟2,3 2跟3 分别进行一对一形成一个分离超平面
clf.fit(X, Y)
dec = clf.decision_function([[1]])#样本到分隔超平面的有符号距离,哪个近就是哪个类别
print(clf.classes_)

(3)回归问题

也分 SVR, NuSVRLinearSVR的类似上面。

from sklearn import svm
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
clf = svm.SVR()
#ovo就是0分别跟1,2,3  1跟2,3 2跟3 分别进行一对一形成一个分离超平面
clf.fit(X, y)
clf.predict([[1, 1]])

(4)密度估计,异常检测

OneClassSVM简介:比如只有一个类别,我们就训练一个最小的球形(有可能是三维及三维以上)超球面,把数据包起来,没有包起来的就是不属于这个类的。
官方代码:

'''
参数
kernel:核函数(一般用高斯核)
nu:设定训练误差(0, 1]
方法
fit(x):训练,根据训练样本和上面两个参数探测边界。(注意是无监督哦!)
predict(x):返回预测值,+1就是正常样本,-1为异常样本。
decision_function(X):返回各样本点到超平面的函数距离(signed distance),正的为正常样本,负的为异常样本。

'''
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager
from sklearn import svm
 
xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
# Generate train data
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
# Generate some regular novel observations
X = 0.3 * np.random.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
# Generate some abnormal novel observations
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))
 
# fit the model
clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1)
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
n_error_train = y_pred_train[y_pred_train == -1].size
n_error_test = y_pred_test[y_pred_test == -1].size
n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
 
# plot the line, the points, and the nearest vectors to the plane
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
 
plt.title("Novelty Detection")
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)  #绘制异常样本的区域
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')  #绘制正常样本和异常样本的边界
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred')   #绘制正常样本的区域
s = 40
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=s, edgecolors='k')
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c='blueviolet', s=s,
                 edgecolors='k')
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='gold', s=s,
                edgecolors='k')
plt.axis('tight')
plt.xlim((-5, 5))
plt.ylim((-5, 5))
plt.legend([a.collections[0], b1, b2, c],
           ["learned frontier", "training observations",
            "new regular observations", "new abnormal observations"],
           loc="upper left",
           prop=matplotlib.font_manager.FontProperties(size=11))
plt.xlabel(
    "error train: %d/200 ; errors novel regular: %d/40 ; "
    "errors novel abnormal: %d/40"
    % (n_error_train, n_error_test, n_error_outliers))
plt.show()

结果:
在这里插入图片描述

(5)自定义核函数

from sklearn import svm
import numpy as np
X = [[1,1],[2,2],[3,8],[5,9]]
y = [0, 0,1,1]
def my_kernel(X, Y):
    return np.dot(X, np.transpose(Y))
clf = svm.SVC(kernel=my_kernel)
clf.fit(X, y)
answer = clf.predict([[2, 2]])

2.手写算法

肝不动了= =睡觉了,有时间再把手撸代码完成

参考:
[1] sklearn文档
[2] 周志华 王魏 高尉 张利军 《机器学习理论导引》
[3] comeonbady 支持向量机(SVC,NuSVC,LinearSVC)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值