机器学习05|一万五字:SVM支持向量机02 jupyter代码详解篇

Posted 湘粤Ian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习05|一万五字:SVM支持向量机02 jupyter代码详解篇相关的知识,希望对你有一定的参考价值。

文章目录


本文用到的所有数据 机器学习05:SVM【代码及数据文件】

本文为SVM支持向量机系列第二篇,主要讲解代码实现及解析。详细实现原理及公式推导,请参考第一篇博客:
机器学习05|一万五字:SVM支持向量机01 【原理详解篇】

Jupyter实现

现在我们来总结下SMO算法的步骤
1 第一步选取一对 α i 和 α j ,选取方法使用启发式方法 \\alpha_i和\\alpha_j,选取方法使用启发式方法 αiαj,选取方法使用启发式方法
2 第二步,固定 除 α i 和 α j 之外的其它参数 , 确定 W 极值条件下的 α i , α j 由 α i 表示。 除\\alpha_i和\\alpha_j之外的其它参数,确定W极值条件下的\\alpha_i,\\alpha_j由\\alpha_i表示。 αiαj之外的其它参数,确定W极值条件下的αi,αjαi表示。
3 第三步,更新乘子,选取乘子的方式如下:
先扫描所有乘子,把第一个违反 K K T 条件的作为更新对象,令为 α 1 先扫描所有乘子,把第一个违反KKT条件的作为更新对象,令为\\alpha_1 先扫描所有乘子,把第一个违反KKT条件的作为更新对象,令为α1
在所有不违反 K K T 条件的乘子中,选择使 ∣ E 1 − E 2 ∣ 最大的 α 2 进行更新,使得能最大限度增大目标函数的值。 在所有不违反KKT条件的乘子中,选择使|E_1-E_2|最大的\\alpha_2进行更新,使得能最大限度增大目标函数的值。 在所有不违反KKT条件的乘子中,选择使E1E2最大的α2进行更新,使得能最大限度增大目标函数的值。

4 最后,每次更新完两个乘子的优化后,都需要再重新计算b,以及对应的 E i E_i Ei值。

经过前面几节的铺垫,我们了解SVM对偶形式的求解,现在我们就来用代码实现SVM。

任务一 从DataSet.txt中导入数据,获得训练集以及标签。

定义函数LoadData(filename),参数为文件名,返回训练数据集以及标签。数据集由两个特征 X 1 和 X 2 X_1和X_2 X1X2构成

#导入相应的库包
from numpy import *
import numpy as np
import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings("ignore",category=DeprecationWarning)  #消除警告
def LoadData(filename):
    data = []
    label = []
    with open(filename) as f:                               
        for line in f.readlines():     #按行读取
            ### START THE CODE ###
            lineArr = line.strip().split('   ')             #消除分隔符
            num = np.shape(lineArr)[0]
            data.append(list(map(float,lineArr[0:num-1]))) #将特征存放到Data中
            label.append(float(lineArr[num-1]))           #将标签存放到Label中
            ### END THE CODE ###
    return data,label

获取训练集,数据和标签

TrainData, TrainLabel = LoadData('DataSet.txt')
print ("TrainData = ",TrainData[:3])
print ("TrainLabel = ",TrainLabel[:3])
TrainData =  [[3.542485, 1.977398], [3.018896, 2.556416], [7.55151, -1.58003]]
TrainLabel =  [-1.0, -1.0, 1.0]

输出:

TrainData = [[3.542485, 1.977398], [3.018896, 2.556416], [7.55151, -1.58003]]

TrainLabel = [-1.0, -1.0, 1.0]

定义所需操作的数据结构DataOp如下

class DataOp(object):
    def __init__(self,data,label,C,toler):      #定义构造函数
        self.X = data                           #数据
        self.label = label                      #标签
        self.C = C                              #松弛变量
        self.tol = toler                        #容忍度
        self.m = shape(data)[0]                 #特征向量的第一个维度
        self.alpha = mat(zeros((self.m,1)))     #Alpha个数初始化
        self.b = 0                              #步长
        self.Cache = mat(zeros((self.m,2)))     #第一列给出是否有效 第二列给出的是实际的E值       

我们利用上述定义的数据结构来表达我们整个训练模型的过程需要的参数以及数据,初始化一个DataOp对象

oS = DataOp(mat(TrainData), mat(TrainLabel).transpose(), 0.6, 0.001)

在选择乘子过程中,我们需要选中两个不同的乘子,所以当我们固定了其中一个乘子,就需要选出不同于第一个乘子的第二个乘子。我们定义一个函数SelectAlpha来实现这个过程。

函数:SelectAlpha(i,m)
作用:随机选择一个整数j,(0<=j<=m-1 && j!=i)
参数:i第一个乘子的下标,m所有alpha的个数
返回:一个随机选择不同于i的下标j

def  SelectAlpha(i,m):
    j = i
    while (j == i):
        j = int(random.uniform(0,m))  
    return j

任务二 调整alpha的值

根据如下规则来对我们计算出的alpha进行调整。
1 α 2 n e w , w n c > H \\alpha_2^new,wnc>H α2new,wnc>H
α 2 n e w = H \\alpha_2^new=H α2new=H
2 L < = α 2 n e w , w n c < = H L<=\\alpha_2^new,wnc<=H L<=α2new,wnc<=H
α 2 n e w = α 2 n e w , w n c \\alpha_2^new=\\alpha_2^new,wnc α2new=α2new,wnc
3 α 2 n e w , w n c < L \\alpha_2^new,wnc<L α2new,wnc<L
α 2 n e w = L \\alpha_2^new=L α2new=L

函数:ResetAlpha(Alphaj,low,high)

作用:调整Alphaj(即 α j \\alpha_j αj)的值,使得low<=Alphaj<=high,调整幅度尽可能小

参数:Alphaj 目标值, low 最小值, high最大值

返回:调整后的Alphaj

def ResetAlpha(Alphaj,low,high):
    ### STARD CODE HERE ###
    if Alphaj >= high:
        Alphaj = high
    elif Alphaj <= low:
        Alphaj = low
    ### END CODE HERE ###
    return Alphaj
a = 10
b = ResetAlpha(a,11,20)
c = ResetAlpha(a,1,8)
print("b = ", b)
print("c = ", c)
b =  11
c =  8

输出:
b = 11
c = 8

任务三 上述原理过程中,需要计算真实值与预测值之间的误差,定义一个函数ComputeEk。

函数 ComputeEk(os,k)

作用:求Ek误差 = 预测值 - 真实值。
真实值即样本标签,以下公式计算预测值 f ( x ) = ∑ i = 1 n α i y i < x i , x > + b f(x)=\\sum_i=1^n\\alpha_iy_i<x_i,x>+b f(x)=i=1nαiyi<xi,x>+b

参数:os DataOp对象,k 具体的某一行

返回:预测值与真实结果对比,计算误差Ek

def ComputeEk(os,k):
    PredictK = float(multiply(os.alpha,os.label).T * (os.X*os.X[k,:].T)) + os.b
    ### START CODE HERE ###
    Ek = PredictK - os.label[k,:]
    ### END CODE HERE ###
    return Ek
Ek1 = ComputeEk(oS,25)
Ek2 = ComputeEk(oS,30)
print ("Ek1 = ", Ek1)
print ("Ek2 = ", Ek2)
Ek1 =  [[-1.]]
Ek2 =  [[1.]]

输出:

Ek1 = -1.0

Ek2 = 1.0

任务四 选取最大 ∣ E i − E j ∣ |E_i-E_j| EiEj最大的j,并返回j以及 E j E_j Ej

函数:SelectMaxJ(i,oS,Ei)

作用:返回差值最大的j和对应的Ej,选择第二个(内循环)值以保证每次优化中采用最大步长。

这里的目标是选择合适的第二个alpha值以保证每次优化中采用最大步长

该函数的误差与第一个alpha值Ei和下标i有关。

参数:

i 具体的第i行

oS DataOp对象

Ei 预测值与真实值对比,计算Ei

返回:

j 随机选出的第j行

Ej 预测结果与真实值对比,计算误差Ej

def SelectMaxj(i,oS,Ei):
    MaxK = -1              #保存最大下标值
    MaxDeltaE = 0          #保存最大步长
    Ej = 0
    oS.Cache[i] = [1,Ei]   #首先将输入值Ei在缓存中设置为有效的。这里意味着它已经计算好了
    List = nonzero(oS.Cache[:,0].A)[0]
    if (len(List)) > 1:               # 在所有的值上进行循环,并选择使得改变最大的那个值
   

以上是关于机器学习05|一万五字:SVM支持向量机02 jupyter代码详解篇的主要内容,如果未能解决你的问题,请参考以下文章

机器学习中的算法:支持向量机(SVM)基础

机器学习简单实践——支持向量机

05-支持向量机 (SVM) 上

机器学习:支持向量机SVM

机器学习 - 支持向量机

机器学习入门之四:机器学习的方法--SVM(支持向量机)(转载)