机器学习之支持向量机SVM及代码示例

来源:互联网 发布:淘宝网加厚牛仔裤 编辑:程序博客网 时间:2024/04/30 04:31

一、线性可分SVM

SVM算法最初是用来处理二分类问题的,是一种有监督学习的分类算法。

对于线性可分的二分类问题,我们可以找到无穷多个超平面,将两类样本进行区分。(超平面:一维中是一个点;二维中是一条线;三维中是一个面……)

这里写图片描述

在上面的多个超平面中,它们都可以成功将样本集划分两边,但哪一个超平面更好?

一般来说,当样本点离超平面越近,样本的标签为某类型的概率应该为0.5左右,确信度比较低,而样本点离超平面越远,样本的标签为某类型的概率越大,确信度比较高。

而线性可分SVM所寻找的最优超平面就是要尽可能的远离所有类别的数据点,使得间隔(margin)最大,利用间隔最大化来求得最优超平面。间隔的定义如下图所示:

这里写图片描述

一般来说,间隔(Margin)中间是无点区域。为了偏袒于某一类样本,超平面到两类样本点集合的最小距离都是相等的,即间隔等于超平面到两类样本集的最小距离*2。对于间隔越大的超平面,分类犯错的机率就越小,分类的确信度就越高。

二、超平面和间隔

接下来,需要做的就是将间隔(Margin)进行最大化,来寻找最优超平面。在这之前,需要对超平面进行定义,以便于计算点到超平面距离。

可将超平面定义为 这里写图片描述,向量 这里写图片描述 为超平面的法向量,标量 b 为截距。

这里写图片描述

这里写图片描述

向量 x 为样本的特征向量。而向量 x 点乘 向量 这里写图片描述 可理解为向量 x 在 向量 w 上未进行归一化的投影。

这里写图片描述

通过这样定义超平面后,由图可以发现:所有在超平面右上方的样本点都有 这里写图片描述 ,所有在超平面左下方的样本点都有 这里写图片描述

当然,所有在超平面上的点都有 这里写图片描述

进一步,我们可以通过等比例缩放 法向量 这里写图片描述 和 截距 b,使得:

这里写图片描述

其中,这里写图片描述 为第 i 个样本的特征向量,并将正样本的标签令作 1,负样本的标签令作 -1;这样这两个式子整合为一个式子:

这里写图片描述

具体效果如图所示:

这里写图片描述

而“支持向量”就是所有落在间隔两边的超平面H1、H2上的点,超平面H1、H2上的任意一点(支持向量)到分界超平面的距离为 这里写图片描述 。因此,隔间的宽度应该为 这里写图片描述

具体的公式推导如下:

这里写图片描述

三、最大化间隔

在上面,我们找到了间隔(margin)的表达式为 这里写图片描述,也找到了向量w的约束条件为 这里写图片描述 。即我们需要在约束条件 这里写图片描述 下得到最大化的间隔。

为了方便计算,这里将 最大化间隔 这里写图片描述 变换为 最小化 这里写图片描述

最后可变换为最优化问题,即:

在约束条件 这里写图片描述 下取得 这里写图片描述 的最小值。

我们可以 拉格朗日乘子法 来解决这个问题。由拉格朗日乘子法,可以得到一个新的函数如下:

这里写图片描述

其中 这里写图片描述 为第i个乘子,且大于等于 0 。

然后在这个函数上分别对 向量 这里写图片描述 和 b 求偏导,并令偏导等于0。可有以下两个等式:

这里写图片描述,可得到 这里写图片描述

这里写图片描述,可得到 这里写图片描述

将上面得出的两个式子代入L函数中,有:

这里写图片描述

可以发现,函数L与训练集中样本的特征向量的两两点乘有关。

接下来,根据拉格郎日对偶性,将原始问题的对偶问题是极大极小问题:

这里写图片描述

接下来求 这里写图片描述这里写图片描述 的极大:

这里写图片描述

s.t. 这里写图片描述这里写图片描述 大于等于 0 .

将极大问题转换为转换为对偶的极小最优化问题:

这里写图片描述

同样 s.t. 这里写图片描述这里写图片描述 大于等于 0 .

通过对 这里写图片描述 偏导 和 对 这里写图片描述 = 0 的情况进行求得最小值 / SMO 算法,可解得到最优解 这里写图片描述

得到最优解 这里写图片描述 后,可得到法向量的最优解 这里写图片描述 ,再将 “支持向量” 代入函数中,通过移项可得到最优解 b 。

支持向量与 这里写图片描述 的关系:当向量 这里写图片描述 不是“支持向量”时,这里写图片描述 等于0;当向量 这里写图片描述 为“支持向量”时,这里写图片描述 不等于0。

因为在决定分离超平面时只有支持向量起作用,SVM训练出来的模型完全依赖于支持向量,即使训练集里面所有 非支持向量的样本点都被去除,结果仍然会得到完全一样的模型。

因此超平面可以表示为:这里写图片描述

其中 这里写图片描述 为待测试的样本的特征向量,这里写图片描述 为 第i个训练样本的标签(1 / -1)。

当将 这里写图片描述 测试样本代入 d 中后,若 d < 0,则测试样本的标签为-1;若 d > 0,则测试样本的标签为1;

四、从硬间隔到软间隔

有些时候,当存在噪声样本时,训练集的样本集并不能被严格地线性可分(即使使用了后面的核函数)。如图所示:
这里写图片描述
如果硬着坚持按照原来的约束条件 这里写图片描述 考虑所有的样本点,在此基础上寻找正负类之间的最大间隔,就会使得整个问题无解。这种解法也叫做“硬间隔”( hard margin )分类法,因为它硬性地要求所有样本点都满足和分类平面间的距离必须大于某个值。

从图中可看出,硬间隔的分类法容易受少数点的控制,为了解决这种控制,可以允许一些点到分类平面的距离不满足原先的要求。

原先我们的硬约束条件为:这里写图片描述

为了引入容错性,对每个样本点引入一个松弛变量 这里写图片描述,现在我们的软约束条件为:

这里写图片描述

当某些点比较特殊时(比较离群),新的约束条件意味着我们放弃了对这些点的精确分类,而这对分类器来说是种损失。但损失这些特殊点也带来了一些好处,那就是使超平面不必向这些点的方向移动,因而可以得到更大的间隔margin。

因为为了权衡这种损失和好处,即减小损失且又扩大间隔,我们的目标函数也需要发生改变,即我们需要最小化的函数为:这里写图片描述

其中n为训练集样本的个数;把损失加入到目标函数后,需要一个惩罚因子C,C是模型的一个超参数 。这种方法也叫作 一阶软间隔分类器

当公式中的 这里写图片描述 的阶为2时,即最小化损失函数为 这里写图片描述 ,这种方法叫作 二阶软间隔分类器

又因为 这里写图片描述 , 因此损失函数可变换为:

这里写图片描述

这里引入了 Hinge Loss这里写图片描述 ,当样本点距离边界太远时,该样本点的 Hinge Loss 为 0 。

当惩罚因子C越大时,被误分类的样本点的个数就越小。上面的公式中,所有样本点共用了一个惩罚因子,当然,也可以是不同的样本点可以对应不同的惩罚因子。

五、从线性到非线性

上面只是说明了线性可分的情况,而针对线性不可分的情况:
这里写图片描述

训练集的样本在当前维度的空间对应的向量找不到一个超平面来区分开。对于这种情况,一种处理方法是 对特征向量进行非线性映射,映射到一个更高维的空间,然后再在高维空间中寻找最优超平面,但计算内积时算法复杂度非常高;另一种处理方法为 核方法(kernel trick),用一个核函数来 取代 经映射之后的向量的内积,解决复杂度的问题。

具体例子可如下图所示:

这里写图片描述

若用f表示这个非线性的映射,那么核函数等同于经f映射之后的两个向量的内积: 这里写图片描述,等式左边的计算复杂度往往低于右边的计算复杂度。

复杂度的比较例子如下图所示:

这里写图片描述

常见的核函数有:

h度多项式核函数:这里写图片描述

高斯核函数RBF:这里写图片描述 , 其中 gamma 为超参数。

一般根据先验知识来选择相应的核函数,可尝试不同的核函数,根据实验结果来确定。

六、从二分类到多分类

在上面,我们讨论的都是使用SVM来二分类问题。对于多分类问题,可以通过扩展SVM,通过one-vs-rest的方法来解决多分类问题,这样的解决方法一般会有很多个SVM:有多少类标签,就会有多少个SVM。

七、SVM与LR的区别

  1. 对于线性模型,决定SVM得到的直线位置并不是所有的训练样本,而是那些支持向量;而逻辑回归模型在训练模型中考虑了所有训练样本对参数的影响。这个可以本质上从损失函数上看出来。

  2. 在解决非线性问题时,支持向量机采用核函数的机制,而LR通常多项式化特征的方法。

  3. 逻辑回归的损失函数是logistic loss,而SVM的损失函数是hinge loss :

八、代码示例

import numpy as npimport matplotlib.pyplotfrom sklearn import svm
np.random.seed(8) # 保证随机的唯一性
# 线性可分:array = np.random.randn(20,2)X = np.r_[array-[3,3],array+[3,3]]y = [0]*20+[1]*20print X[0]print X[20]print y
[-2.90879528 -1.90871727][ 3.09120472  4.09128273][0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
# 建立svm模型clf = svm.SVC(kernel='linear')clf.fit(X,y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,  decision_function_shape=None, degree=3, gamma='auto', kernel='linear',  max_iter=-1, probability=False, random_state=None, shrinking=True,  tol=0.001, verbose=False)
x1_min, x1_max = X[:,0].min(), X[:,0].max(),x2_min, x2_max = X[:,1].min(), X[:,1].max(),xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))# 得到向量w  : w_0x_1+w_1x_2+b=0w = clf.coef_[0]f = w[0]*xx1 + w[1]*xx2 + clf.intercept_[0]+1  # 加1后才可绘制 -1 的等高线 [-1,0,1] + 1 = [0,1,2]plt.contour(xx1, xx2, f, [0,1,2], colors = 'r') # 绘制分隔超平面、H1、H2plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.Paired) plt.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],color='k') # 绘制支持向量点plt.show()

这里写图片描述

# 非线性可分:from sklearn import datasets
# 加载数据iris = datasets.load_iris()X = iris.datay = iris.targetprint iris.target_names
['setosa' 'versicolor' 'virginica']
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3.) # 分割训练集和测试集
from sklearn.preprocessing import StandardScaler # 标准化scaler = StandardScaler()X_train_std = scaler.fit_transform(X_train)X_test_std = scaler.transform(X_test)
from sklearn.grid_search import GridSearchCV
# 交叉验证,调整参数param_grid = {'C':[1e1,1e2,1e3, 5e3,1e4,5e4],              'gamma':[0.0001,0.0008,0.0005,0.008,0.005,]}clf = GridSearchCV(svm.SVC(kernel='rbf',class_weight='balanced'),param_grid,cv=10)clf = clf.fit(X_train_std,y_train)print clf.best_estimator_
SVC(C=10.0, cache_size=200, class_weight='balanced', coef0=0.0,  decision_function_shape=None, degree=3, gamma=0.005, kernel='rbf',  max_iter=-1, probability=False, random_state=None, shrinking=True,  tol=0.001, verbose=False)
clf.score(X_test_std,y_test)
1.0
y_pred = clf.predict(X_test_std)
from sklearn.metrics import classification_reportfrom sklearn.metrics import confusion_matrix
print(classification_report(y_test,y_pred,target_names=iris.target_names))print(confusion_matrix(y_test,y_pred,labels=range(iris.target_names.shape[0])))
             precision    recall  f1-score   support     setosa       1.00      1.00      1.00        18 versicolor       1.00      1.00      1.00        17  virginica       1.00      1.00      1.00        15avg / total       1.00      1.00      1.00        50# recall表示召回率 = #(True positive) / (#(True positive)+ #(False negative)),表示样本中的正例有多少被预测正确。# precision表示精确率 = #(True positive) / (#(True positive)+ #(False negative)),表示预测为正的样本中有多少是真正的正样本。# f1-score(F1指标)表示召回率和精确率两个指标的调和平均数,召回率和精确率越接近,F1指标越高。F1 = 2 / (1/recall + 1/precision)。召回率和精确率差距过大的学习模型,往往没有足够的实用价值。[[18  0  0] [ 0 17  0] [ 0  0 15]]纵坐标表示预测的是谁,横坐标表示标准的是谁。对角线的值越大,预测能力越好。
1 0