机器学习之支持向量机

机器学习中另一种重要的算法是支持向量机,简称SVM。下面我们就这个算法进行介绍。

首先支持向量机的整体思路是:

 简单情况,线性可分,把问题转化为一个凸优化问题,可以用拉格朗日乘子法简化,
然后用既有的算法解决
 复杂情况,线性不可分,用映射函数将样本投射到高维空间,使其变成线性可分的情
形。利用核函数来减少高维度计算量

这个思路的具体实现是什么呢,首先考虑样本集线性可分情况

简单情况,线性可分

如上图,如何选取最优的分离平面(决策边界)?

就好比所有数据点都是地雷,现在要找出一条最大边界,使得部队能够快速的通过。像下图中

这两个边界都可以让部队通过,但是右边的路线能是部队快速的通过,这个就是支持向量机(SVM)要做的事情。而通道上紧挨着的3个数据点,在这里叫做“支持向量”。。

好了,下面我们就要对SVM进行一步一步的算法分析,怎么能够得到这条最大的边界。

上图中我们假设最优的分离平面是w.x+b = 0

上边界定义为w.x+b = 1,数据点x1位于上边界上

下边界定义为w.x+b = -1,数据点x2位于下边界上。(注意,这里w.x是点乘,内积)

而我们要求解的是两个边界的最大距离d

用将上下边界上的点带入到边界上,并用上边界减去下边界可得

w.(x1-x2) = 2

而根据内积的几个意义可知

w.(x1-x2) = 2---------------->||w||*||x1-x2||*cosθ = 2 (θ为x1与x2向量和距离d的夹角)

所以。||w||*||x1-x2||*cosθ = 2  ---------------->||w||*d = 2由此可得   d = 2/||w||。。。。

到这里我们的目标是优化d = 2/||w||,使得d最大。而条件是

(因为是分类。)

而这样的“如果”是不方便我们进行数学计算的,并且按照通常的思路,求极大值问题的时候我们往往转换成求极小值问题。所以我们进行整理则有

到这里,似乎有些进行不下去了。这时候需要用到-------------拉格朗日乘子法。。。。

将上图中的式子进行转换

其中α是拉格朗日乘子。

根据拉格朗日乘子法我们要求解L(w,b,a)的最大值

对w和b分别求导可得

将上述带回到

 

最终呢,我们得到的一个带约束条件的式子:

到这里,还有一种情况,需要我们加入松弛变量和惩罚函数

如上图这种情况,有部分黑色的点在白色区域内,同样部分白色点在黑色区域内。由于这些异常点存在。我们不能完全分离。加入松弛变量和惩罚函数,就是使得边界到这些异常点越近越好。所以将原来的需求变成如下形式。

其中C越大惩罚力度越大,我们找到的一个分隔区域越窄。C越小惩罚力度越小,我们找到这个分隔区域越宽。

最后经过拉格朗日乘子法可得

由此看出,跟原来没有加惩罚函数和松弛变量的式子区别在于限制条件的变化。

到这里,最后要怎么计算这个式子,得出结果呢

就是采用SMO算法,这个算法有兴趣的朋友可以自行百度了解一下。

主要的思路是:空出两个乘子后,其余乘子随机赋值。通过上面的式子计算出这两个没有赋值的乘子。每次只更新两个乘子,最后反复迭代,知道空出的两个乘子不再变化。

复杂情况,线性不可分

而对于线性不可分的情况。思路就是将低维不可分的映射到高维可分。

公式中红字的地斱要使用映射后的样本向量代替做内积

但是高维映射会导致维度灾难

最初的特征是n维的,我们将其映射到n^2维,然后再计算,这样需要的时间从原先的O(n)变成O(n^2)
因此,我们引入核函数。

举个例子:

在一组房价的数据集中,特征是房子的面积x,这里的x是实数,结果y是房子的价格。假设我们从样本点的分布中看到x和y符合3次曲线,那么我们希望使用x的三次多项式来逼近这些样本点。那么首先需要将特征x扩展到三维clip_image002[6],然后寻找特征和结果之间的模型。我们将这种特征变换称作特征映射(feature mapping)。映射函数称作clip_image004[10],在这个例子中

我们将得到的特征映射后的特征应用于SVM分类,而不是最初的特征。这样,我们需要将前面clip_image008[4]公式中的内积从clip_image010[16],映射到clip_image012[42]。如果要实现该开头的式子,只需先计算clip_image020[10],然后计算clip_image022[10]即可,然而这种计算方式是非常低效的。比如最初的特征是n维的,我们将其映射到clip_image024[6]维,然后再计算,这样需要clip_image026[6]的时间。

假设展开后

这个时候发现我们可以只计算原始特征x和z内积的平方(时间复杂度是O(n)),就等价与计算映射后特征的内积。也就是说我们不需要花clip_image026[7]时间了。

最后给出常用的核函数

有了核函数后可以将上面的拉格朗日函数简化

 

最后我们用代码来使用SVM

import numpy as np
import pylab as pl
from sklearn import svm

而使用的数据集是一个非常有名的用于分类问题的数据集:鸢尾花数据集。它是基于鸢尾花的花萼的长度和宽度进行分类的。我们只用其中两维特征,这能够方便可视化。

svc = svm.SVC(kernel='linear')
# 鸢尾花数据集是sklearn自带的。
from sklearn import datasets
iris = datasets.load_iris()
# 只提取前面两列数据作为特征
X = iris.data[:, :2]
y = iris.target
# 基于这些数据训练出一个支持向量分离器SVC
svc.fit(X, y)

数据结果可视化

from matplotlib.colors import ListedColormap
# 因为鸢尾花是3分类问题,我们要对样本和预测结果均用三种颜色区分开。
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

def plot_estimator(estimator, X, y):
    '''
    这个函数的作用是基于分类器,对预测结果与原始标签进行可视化。
    '''
    estimator.fit(X, y)
    # 确定网格最大最小值作为边界
    x_min, x_max = X[:, 0].min() - .1, X[:, 0].max() + .1
    y_min, y_max = X[:, 1].min() - .1, X[:, 1].max() + .1
    # 产生网格节点
    xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100),
                         np.linspace(y_min, y_max, 100))
    # 基于分离器,对网格节点做预测
    Z = estimator.predict(np.c_[xx.ravel(), yy.ravel()])

    # 对预测结果上色
    Z = Z.reshape(xx.shape)
    pl.figure()
    pl.pcolormesh(xx, yy, Z, cmap=cmap_light)

    # 同时对原始训练样本上色
    pl.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold)
    pl.axis('tight')
    pl.axis('off')
    pl.tight_layout()
plot_estimator(svc, X, y)

 

而加入惩罚函数和松弛变量

svc = svm.SVC(kernel='linear', C=1e3)
plot_estimator(svc, X, y)
pl.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=80, facecolors='none', zorder=10)
pl.title('High C values: small number of support vectors')

svc = svm.SVC(kernel='linear', C=1e-3)
plot_estimator(svc, X, y)
pl.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=80, facecolors='none', zorder=10)
pl.title('Low C values: high number of support vectors')

在试试利用核函数

采用核方法,能够很方便地产生非线性分类边界。

  • linear,线性核,会产生线性分类边界。一般来说它的计算效率最高,而且需要数据最少。
  • poly ,多项式核,会产生多项式分类边界。
  • rbf,径向基函数,也就是高斯核,是根据与每一个支持向量的距离来决定分类边界的。它的映射到无线维的。它是最灵活的方法,但是也需要最多的数据。
svc = svm.SVC(kernel='linear')
plot_estimator(svc, X, y)
pl.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=80, facecolors='none', zorder=10)
pl.title('Linear kernel')

svc = svm.SVC(kernel='poly', degree=4)
plot_estimator(svc, X, y)
pl.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=80, facecolors='none', zorder=10)
pl.title('Polynomial kernel')

svc = svm.SVC(kernel='rbf', gamma=1e2)
plot_estimator(svc, X, y)
pl.scatter(svc.support_vectors_[:, 0], svc.support_vectors_[:, 1], s=80, facecolors='none', zorder=10)
pl.title('RBF kernel')

我们可以看到,高斯核更灵活,而且对于训练数据效果是最好的。但是要担心过拟合。

最后,支持向量机SVM是一个在机器学习中常见的算法,虽然正逐渐被神经网络慢慢替代,但是其算法的思想是我们要掌握的。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值