机器学习实战-支持向量机

感知器模型

感知器模型就是试图找到一条线,能够将所有的二元类别分割开。如果是高维空间就是找到一个超平面,能够将所有的二元类别分割开。算法是在数据中找出一个划分超平面,让尽可能的数据分布在这个平面的两侧。实际中符合要求的超平面是可能存在多个点的。

模型的核心思想,让距离超平面最近的点尽可能的远离超平面。

SVM几个重要名词解释

1,线性可分:在数据集中可以找出一个超平面,将两组数据分开,这个数据集叫线性可分数据

2,线性不可分:在数据集中,没法找出一个超平面,能够将两组数据分开,

3,分隔超平面:将数据分割开来的直线/平面

4,支持向量:离分隔超平面最近的那些点叫做支持向量

5,间隔,支持向量数据到分隔超平面的距离。

在svm中,支持向量到超平面的函数狐狸一般设置为1

6.2.2 SVM应用的一般框架

'''
SVM的一般流程
1)收集数据:可以使用任意方法。
2)准备数据:需要数值型数据。
3)分析数据:有助于可视化分隔超平面
4)训练算法:SVM的大部分时间都源自训练,改过程主要实现两个参数的调优
5)测试算法:十分简单的计算过程就可以实现
6)使用算法:几乎所有问题都可以使用svm,svm本身就是一个二类分类器,对多类问题应用svm需要对代码做修改
'''

6.3 SMO高效优化算法

所有需要做的围绕优化的事情就是训练分类器,一旦得到appha的最优值,我们就得到了分隔超平面并能够将之用于数据分类

6.3.1Platt的SMO算法

SMO表示序列最小化,将大优化问题分解为多个小优化问题来求解。目标是求出一系列alpha和b,通过alpha,计算出权重向量w并得到分隔超平面

SMO工作原理:每次循环中选择两个alpha进行优化处理。一旦找到一对合适的alpha,那么久增大其中一个同时减少另一个。

6.3.2 应用简化版SMO算法处理小规模数据集

'''
SMO算法的伪代码大致如下
创建一个alpha向量并将其初始化为0向量
当迭代次数小于最大迭代次数时(外循环)
    对数据集中的每个数据向量(内循环)
        如果该数据向量可以被优化
            随机选择另外一个数据向量
            同时优化这两个向量
            如果两个向量都不能被优化,退出内循环
    如果所有向量都没被优化,增加迭代数目,继续下一次循环

'''
#5个参数分别是数据集,类别标签,常数c,容错率toler,取消前最大循环次数
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    dataMatrix = mat(dataMatIn);
    labelMat = mat(classLabels).transpose()#转置了类别标签,变为列向量
    b = 0;
    m, n = shape(dataMatrix)
    alphas = mat(zeros((m, 1)))
    iter = 0
    while (iter < maxIter):
        alphaPairsChanged = 0 #记录是否已经进行了优化
        for i in range(m):
            fXi = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[i, :].T)) + b  #预测的类别
            Ei = fXi - float(labelMat[i])  # if checks if an example violates KKT conditions
            if ((labelMat[i] * Ei < -toler) and (alphas[i] < C)) or ((labelMat[i] * Ei > toler) and (alphas[i] > 0)):#对该值进行优化,位于此处
                j = selectJrand(i, m) #随机选择第二个alpha
                fXj = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b
                Ej = fXj - float(labelMat[j])
                alphaIold = alphas[i].copy();
                alphaJold = alphas[j].copy();
                #保证alpha 在0和C之间
                if (labelMat[i] != labelMat[j]):
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C + alphas[j] - alphas[i])
                else:
                    L = max(0, alphas[j] + alphas[i] - C)
                    H = min(C, alphas[j] + alphas[i])
                if L == H: print("L==H"); continue
                eta = 2.0 * dataMatrix[i, :] * dataMatrix[j, :].T - dataMatrix[i, :] * dataMatrix[i, :].T - dataMatrix[
                                                                                                            j,
                                                                                                            :] * dataMatrix[
                                                                                                                 j, :].T
                if eta >= 0: print("eta>=0"); continue
                alphas[j] -= labelMat[j] * (Ei - Ej) / eta
                alphas[j] = clipAlpha(alphas[j], H, L)
                if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough"); continue
                #对i进行修改,修改量于j相同,但方向相反
                alphas[i] += labelMat[j] * labelMat[i] * (alphaJold - alphas[j])  # update i by the same amount as j
                # the update is in the oppostie direction
                b1 = b - Ei - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[i, :].T - labelMat[
                    j] * (alphas[j] - alphaJold) * dataMatrix[i, :] * dataMatrix[j, :].T
                #设置常数项
                b2 = b - Ej - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[j, :].T - labelMat[
                    j] * (alphas[j] - alphaJold) * dataMatrix[j, :] * dataMatrix[j, :].T
                if (0 < alphas[i]) and (C > alphas[i]):
                    b = b1
                elif (0 < alphas[j]) and (C > alphas[j]):
                    b = b2
                else:
                    b = (b1 + b2) / 2.0
                alphaPairsChanged += 1
                print("iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged))
        if (alphaPairsChanged == 0):
            iter += 1
        else:
            iter = 0
        print("iteration number: %d" % iter)
    return b, alphas

dataarr, labelarr = loadDataSet('testSet.txt')
b,alphas=smoSimple(dataarr,labelarr,0.6,0.001,40)
print(b)rint(alphas[alphas>0])
print(shape(alphas[alphas>0])) //支持向量的个数
for i in range(100):
    if alphas[i]>0:print(dataarr[i],labelarr[i])


....
iteration number: 39
j not moving enough
j not moving enough
iteration number: 40[-3.79937187]]
[[0.13280856 0.23133738 0.00221044 0.36635638]]
(1, 4)
[4.658191, 3.507396] -1.0
[3.457096, -0.082216] -1.0
[2.893743, -1.643468] -1.0
[6.080573, 0.418886] 1.0

基于上面数据,对支持向量画圈结果

from numpy import *
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

xcord0 = []
ycord0 = []
xcord1 = []
ycord1 = []
markers =[]
colors =[]
fr = open('testSet.txt')#this file was generated by 2normalGen.py
for line in fr.readlines():
    lineSplit = line.strip().split('\t')
    xPt = float(lineSplit[0])
    yPt = float(lineSplit[1])
    label = int(lineSplit[2])
    if (label == -1):
        xcord0.append(xPt)
        ycord0.append(yPt)
    else:
        xcord1.append(xPt)
        ycord1.append(yPt)

fr.close()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord0,ycord0, marker='s', s=90)
ax.scatter(xcord1,ycord1, marker='o', s=50, c='red')
plt.title('Support Vectors Circled')

circle = Circle((4.658191, 3.507396), 0.5, facecolor='none', edgecolor=(0,0.8,0.8), linewidth=2, alpha=0.5)
ax.add_patch(circle)
circle = Circle((3.457096, -0.082216), 0.5, facecolor='none', edgecolor=(0,0.8,0.8), linewidth=3, alpha=0.5)
ax.add_patch(circle)
circle = Circle((2.893743, -1.643468), 0.5, facecolor='none', edgecolor=(0,0.8,0.8), linewidth=3, alpha=0.5)
ax.add_patch(circle)
circle = Circle((6.080573, 0.418886), 0.5, facecolor='none', edgecolor=(0,0.8,0.8), linewidth=3, alpha=0.5)
ax.add_patch(circle)
#plt.plot([2.3,8.5], [-6,6]) #seperating hyperplane
#plt.plot([2.3,8.5], [-6,5]) #seperating hyperplane
b = -3.75567; w0=0.8065; w1=-0.2761
x = arange(-2.0, 12.0, 0.1)
y = (-w0*x - b)/w1
ax.plot(x,y)
ax.axis([-2,12,-8,6])
plt.savefig('2.png');
plt.show()

6.4 利用完整Platt SMO 算法加速优化

...

6.5.1 利用核函数将数据映射到高维空间

将数据从一个特征空间转换到另一个特征空间,将这个空间称为从一个特征空间到另一个特征空间的映射。通常情况下,这种映射会将低维特征空间映射到高维空间

这种映射,是通过核函数来实现的

6.5.2径向基核函数

svm中常用的一个核函数,径向基函数是一个采用向量作为自变量的函数,能够基于向量距离运算输出一个标量。

k(x,y)=exp(\frac{-\left \| x-y \right \|^2}{2\sigma ^2}) 

#核转换函数
def kernelTrans(X, A, kTup):  # calc the kernel or transform data to a higher dimensional space
    m, n = shape(X)
    K = mat(zeros((m, 1)))
    if kTup[0] == 'lin':
        K = X * A.T  # linear kernel
    elif kTup[0] == 'rbf':
        for j in range(m):
            deltaRow = X[j, :] - A
            K[j] = deltaRow * deltaRow.T
        K = exp(K / (-1 * kTup[1] ** 2))  # divide in NumPy is element-wise not matrix like Matlab
    else:
        raise NameError('Houston We Have a Problem -- \
    That Kernel is not recognized')
    return K

6.6手写识别问题回顾

在选择算法的时候,如果在性能不变的情况下,使用更少的内存。可以考虑使用支持向量机,支持向量机只需要保存支持向量

通过改变径向基函数的参数,结论:

1,最小的训练错误率并不对应与最小的支持向量数目。

2,线性核函数的效果并不是特别的槽糕。可以牺牲线性核函数的错误率来换取分类速度的提高

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值