机器学习实战刻意练习 —— Task 03. 支持向量机

机器学习实战刻意练习

第 1 周任务
  分类问题:K-邻近算法
  分类问题:决策树

第 2 周任务
  分类问题:朴素贝叶斯
  分类问题:逻辑回归

第 3 周任务
  分类问题:支持向量机

第 4 周任务
  分类问题:AdaBoost

第 5 周任务
  回归问题:线性回归、岭回归、套索方法、逐步回归等
  回归问题:树回归

第 6 周任务
  聚类问题:K均值聚类
  相关问题:Apriori

第 7 周任务
  相关问题:FP-Growth

第 8 周任务
  简化数据:PCA主成分分析
  简化数据:SVD奇异值分解
    



支持向量机



1.简介

支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)。
SVM使用铰链损失函数(hinge loss)计算经验风险(empirical risk)并在求解系统中加入了正则化项以优化结构风险(structural risk),是一个具有稀疏性和稳健性的分类器 。SVM可以通过核方法(kernel method)进行非线性分类,是常见的核学习(kernel learning)方法之一 。
SVM被提出于1964年,在二十世纪90年代后得到快速发展并衍生出一系列改进和扩展算法,在人像识别、文本分类等模式识别(pattern recognition)问题中有得到应用。

  支持向量机(Suport Vector Machine,常简称为SVM),是一个监督式学习的方式。支持向量机属于一般化线性分类器,这类分类器的特点是能够同时最小化经验误差与最大化几何边缘区,因此支持向量机机也被称为最大边缘区分类器。
SVM
max margin
  蓝色和红色的线圈出来的点就是所谓的支持向量,离分界线最近的点,如果去掉这些点,直线多半要改变位置。Classifier Boundary就是决策函数f(x),在两个类的中间。红色和蓝色之间的间隙就是我们要的最大化分类的间隙。


1.1. 拉格朗日乘子法

  有拉格朗日乘子法的地方,必然是一个组合优化问题。比如
     m i n f = 2 x 1 2 + 3 x 2 2 + 7 x 3 2 min f=2x_1^{2}+3x_2^{2}+7x_3^{2} minf=2x12+3x22+7x32
        s . t . s.t. s.t. 2 x 1 + x 2 = 1 2x_1+x_2=1 2x1+x2=1
           2 x 2 + 3 x 3 = 2 2x_2+3x_3=2 2x2+3x3=2
  这是一个带等式约束的优化问题,有目标值,有约束条件,不能直接求导。可以使用拉格朗日方法,把这个约束乘以一个系数加到目标函数中去,这样相当与既考虑了原目标函数,也考虑了约束条件。然后分别对x求导等于0,
∂ f ∂ x 1 = 4 x 1 + 2 α 1 = 0 ⟹ x 1 = − 0.5 α 1 \frac{\partial f}{\partial x_1} = 4x_1+2α_1=0\Longrightarrow x_1=-0.5α_1 x1f=4x1+2α1=0x1=0.5α1

∂ f ∂ x 2 = 6 x 2 + α 1 + 2 α 2 = 0 ⟹ x 2 = − α 1 + 2 α 2 6 \frac{\partial f}{\partial x_2} = 6x_2+α_1+2α_2=0\Longrightarrow x_2=-\frac{α_1+2α_2}{6} x2f=6x2+α1+2α2=0x2=6α1+2α2

∂ f ∂ x 3 = 14 x 3 + 3 α 2 = 0 ⟹ x 3 = − 3 α 2 14 \frac{\partial f}{\partial x_3} = 14x_3+3α_2=0\Longrightarrow x_3=-\frac{3α_2}{14} x3f=14x3+3α2=0x3=143α2

  把它带点菜约束条件中去,可以看到,2个变量两个等式,最终可再带回去求x就可以了。更高一层,带有不等式的约束问题怎么办?需要用更一般化的拉格朗日乘子法,即KKT条件,来求解这个问题。


1.2. KKT条件

  任何原始问题约束条件无非最多三种,等式约束,大于号约束,小于号约束,而这三种最终通过将约束方程简化成两类:约束方程等于0和约束方程小于0。

  假设原始问题约束条件为下例所示:
     m i n f = x 1 2 − 2 x 1 + 1 + x 2 2 + 4 x 2 + 4 min f=x_1^{2}-2x_1+1+x_2^{2}+4x_2+4 minf=x122x1+1+x22+4x2+4
        s . t . s.t. s.t. x 1 + 10 x 2 > 10 x_1+10x_2>10 x1+10x2>10
          10 x 1 + 10 x 2 < 10 10x_1+10x_2<10 10x1+10x2<10
  那么把约束条件变个样子
        s . t . s.t. s.t. 10 − x 1 − 10 x 2 < 0 10-x_1-10x_2<0 10x110x2<0
          10 x 1 − 10 x 2 − 10 < 0 10x_1-10x_2-10<0 10x110x210<0
  现在拿到目标函数中去变成
     L ( x , α ) = f ( x ) + α 1 g 1 ( x ) + α 2 g 2 ( x ) L(x,α)=f(x)+α_1g_1(x)+α_2g_2(x) L(x,α)=f(x)+α1g1(x)+α2g2(x)
         = x 1 2 + 2 x 1 + 11 + x 2 2 + 4 x 2 + 4 + α 1 ( 10 − x 1 − 10 x 2 ) + α 2 ( 10 x 1 − 10 x 2 − 10 ) =x_1^{2}+2x_1+11+x_2^{2}+4x_2+4+α_1(10-x_1-10x_2)+α_2(10x_1-10x_2-10) =x12+2x1+11+x22+4x2+4+α1(10x110x2)+α2(10x110x210)
  那么KKT条件的定理是什么呢?就是如果一个优化问题在转变成
L ( x , α , β ) = f ( x ) + ∑ α i g i ( x ) + ∑ β i h i ( x ) L(x,α,β)=f(x)+\sum_{}α_ig_i(x)+\sum_{}β_ih_i(x) L(x,α,β)=f(x)+αigi(x)+βihi(x)

  其中g是不等式约束,h是等式约束。那么KKT条件就是函数的最优值,它必定满足下面条件:

  1. L对各个x求导为0
  2. h ( x ) = 0 h(x)=0 h(x)=0
  3. ∑ α i g i ( x ) = 0 , α i ≤ 0 \sum_{}α_ig_i(x)=0,α_i\leq 0 αigi(x)=0,αi0

  这三个等式很好理解,重点是第三个句子不好理解,因为我们知道在约束条件变完或,所有的 g ( x ) ≤ 0 g(x) \le 0 g(x)0,且求和还要为0。那么为什么KKT的条件是这样的呢?
  某次的 g ( x ) g(x) g(x)在为最优解起作用,那么它的系数值(可以)不为0,如果某次 g ( x ) g(x) g(x)没有为下一次的最优解起作用,那么它的系数就必须为0。


1.3. 对偶算法

  为了求解线性可分支持向量机的最优化问题,将它作为原始最优化问题,应用到拉格朗日对偶性,通过求解对偶问题得到原始问题的最优解,这就是线性可支持向量机的对偶算法(dual algorithm)。这样做的优点,一是对偶问题往往根据容易求解;二是自然引入核函数,进而推广到非线性可分类问题。

  首先构建拉格朗日函数(Lagrange function)。为此,对每一个不等式约束引入拉格朗日乘子(Lagrange multiplier) α i ≥ 0 , i = 1 , 2 , . . . , N α_i\geq 0,i=1,2,...,N αi0,i=1,2,...,N定义拉格朗日函数:
L ( ω , b , α ) = 1 2 ∣ ∣ ω ∣ ∣ 2 − ∑ i = 1 N α i y i ( ω ∗ x i + b ) + ∑ i = 1 N α i L(\omega,b,α)=\frac{1}{2}||\omega||^{2}-\sum_{i=1}^Nα_iy_i(\omega*x_i+b)+\sum_{i=1}^Nα_i L(ω,b,α)=21ω2i=1Nαiyi(ωxi+b)+i=1Nαi

  其中 α = ( α 1 , α 2 , … , α N ) T \alpha=(\alpha_1,\alpha_2,\dots,\alpha_N)^T α=(α1,α2,,αN)T为拉格朗日乘子向量。
  根据拉格朗日对偶性,原始问题的对偶问题是极大极小问题 m a x α min ⁡ ω , b L ( ω , b , α ) \mathop{max}_{\alpha}\mathop{\min}_{\omega,b}L(\omega,b,\alpha) maxαminω,bL(ω,b,α)

  为了得到对偶函数问题的解,需要先求 L ( ω , b , α ) L(\omega,b,\alpha) L(ω,b,α) ω , b \omega,b ω,b的极小,再求 α \alpha α的极大
  (1)求 min ⁡ ω , b L ( ω , b , α ) \mathop{\min}_{\omega,b}L(\omega,b,\alpha) minω,bL(ω,b,α)
  将拉格朗日函数 L ( ω , b , α L(\omega,b,\alpha L(ω,b,α)分别对 ω , b \omega,b ω,b求偏导数并令其等于 0 0 0
▽ ω L ( ω , b , α ) = ω − ∑ i = 1 N α i y i x i = 0 ▽ b L ( ω , b , α ) = − s u m i = 1 N α i y i = 0 ω = ∑ i = 1 N α i y i x i = 0   ( 1 ) ∑ i = 1 N α i y i = 0   ( 2 ) \begin{matrix}\bigtriangledown_{\omega}L(\omega,b,\alpha)=\omega-\sum_{i=1}^N\alpha_iy_ix_i=0 \\ \bigtriangledown_bL(\omega,b,\alpha) = -sum_{i=1}^N\alpha_iy_i=0 \\ \omega = \sum_{i=1}^N\alpha_iy_ix_i=0 \space(1) \\ \sum_{i=1}^N\alpha_iy_i=0 \space(2) \end{matrix} ωL(ω,b,α)=ωi=1Nαiyixi=0bL(ω,b,α)=sumi=1Nαiyi=0ω=i=1Nαiyixi=0 (1)i=1Nαiyi=0 (2)

  将(1)代入拉格朗日函数,并利用(2),即可得
L ( ω , b , α ) = − 1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j ( x i ∗ x j ) − ∑ i = 1 N α i y i ( ( ∑ j = 1 N α j y j x j ) ∗ x i + b ) + ∑ i = 1 N α i − 1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j ( x i ∗ x j ) + ∑ i = 1 N α i \begin{matrix}L(\omega,b,\alpha)=-\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i*x_j)-\sum_{i=1}^N\alpha_iy_i((\sum_{j=1}^N\alpha_jy_jx_j)*x_i+b)+ \sum_{i=1}^N\alpha_i \\ -\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i*x_j)+\sum_{i=1}^N\alpha_i \end{matrix} L(ω,b,α)=21i=1Nj=1Nαiαjyiyj(xixj)i=1Nαiyi((j=1Nαjyjxj)xi+b)+i=1Nαi21i=1Nj=1Nαiαjyiyj(xixj)+i=1Nαi

  即
min ⁡ ω , b = − 1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j ( x i ∗ x j ) + ∑ i = 1 N α i \mathop{\min}_{\omega,b}=-\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i*x_j)+\sum_{i=1}^N\alpha_i minω,b=21i=1Nj=1Nαiαjyiyj(xixj)+i=1Nαi

  (2)求 min ⁡ ω , b \mathop{\min}_{\omega,b} minω,b α \alpha α的极,即对偶问题
m a x ω   − 1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j ( x i ∗ x j ) + ∑ i = 1 N α i   ( 3 ) \mathop{max}_{\omega} \space -\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i*x_j)+\sum_{i=1}^N\alpha_i \space(3) maxω 21i=1Nj=1Nαiαjyiyj(xixj)+i=1Nαi (3)

s . t .   ∑ i = 1 N α i y i = 0 ( α i ≥ 0 , i = 1 , 2 , … , N ) s.t. \space \sum_{i=1}^N\alpha_iy_i = 0(\alpha_i \ge 0 ,i=1,2,\dots,N) s.t. i=1Nαiyi=0(αi0,i=1,2,,N)

  将公式(3)的目标函数由极大值转换成求极小,就得到下面与之等价的对偶最优化问题
m i n ω   1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j ( x i ∗ x j ) + ∑ i = 1 N α i   ( 3 ) \mathop{min}_{\omega} \space \frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_j(x_i*x_j)+\sum_{i=1}^N\alpha_i \space(3) minω 21i=1Nj=1Nαiαjyiyj(xixj)+i=1Nαi (3)

s . t .   ∑ i = 1 N α i y i = 0 ( α i ≥ 0 , i = 1 , 2 , … , N )   ( 4 ) s.t. \space \sum_{i=1}^N\alpha_iy_i = 0(\alpha_i \ge 0 ,i=1,2,\dots,N) \space(4) s.t. i=1Nαiyi=0(αi0,i=1,2,,N) (4)

  (3)解 ω ∗ , b ∗ \omega^*,b^* ω,b
  假设 α ∗ = ( α 1 ∗ , α 2 ∗ , … , α l ∗ ) T \alpha^*=(\alpha_1^*,\alpha_2^*,\dots,\alpha_l^*)^T α=(α1,α2,,αl)T是对偶最优化问题的解,则存在下标使得 α j ∗ > 0 \alpha_j^* > 0 αj>0,并求按下式求得原始最优化的解 ω ∗ , b \omega^*,b ω,b

  根据KKT条件成立,即得
▽ ω L ( ω ∗ , b ∗ , α ∗ ) = ω ∗ − ∑ i = 1 N α i ∗ y i x i = 0 ▽ b L ( ω ∗ , b ∗ , α ∗ ) = − ∑ i = 1 N α i ∗ y i = 0 α i ∗ ( y i ( ω ∗ ∗ x i + b ∗ ) − 1 ) ≥ 0 , i = 1 , 2 , … , N y i ( ω ∗ ∗ x i + b ∗ ) − 1 ≥ 0 , i = 1 , 2 , … , N α i ∗ ≥ 0 , i = 1 , 2 , … , N \begin{matrix}\bigtriangledown_{\omega}L(\omega^*,b^*,\alpha^*) = \omega^*-\sum_{i=1}^N\alpha_i^*y_ix_i = 0 \\ \bigtriangledown_b L(\omega^*,b^*,\alpha^*)=-\sum_{i=1}^N \alpha_i^*y_i =0 \\ \alpha_i^*(y_i(\omega^**x_i+b^*)-1) \ge 0,i=1,2,\dots,N \\ y_i(\omega^**x_i+b^*)-1 \ge 0,i =1,2,\dots,N \\ \alpha_i^* \ge 0 ,i =1,2,\dots,N \end{matrix} ωL(ω,b,α)=ωi=1Nαiyixi=0bL(ω,b,α)=i=1Nαiyi=0αi(yi(ωxi+b)1)0,i=1,2,,Nyi(ωxi+b)10,i=1,2,,Nαi0,i=1,2,,N

  因此 ω ∗ = ∑ i = 1 N α i ∗ y i x i   ( 5 ) \omega^*=\sum_{i=1}^N \alpha_i^*y_ix_i\space(5) ω=i=1Nαiyixi (5)

   y j 2 = 1 y_j^2=1 yj2=1,且至少存在一个 α j > 0 \alpha_j > 0 αj>0,假设, α ∗ = 0 \alpha^* = 0 α=0,那么 ω = 0 \omega= 0 ω=0不是原始问题的解,所以
b ∗ = y j − ∑ i = 1 N α i ∗ y i ( x i ∗ x j )   ( 6 ) b^{*}=y_j-\sum_{i=1}^N \alpha_i^*y_i(x_i*x_j) \space(6) b=yji=1Nαiyi(xixj) (6)

  那么分离的超平面可以写成 ∑ i = 1 N α i ∗ y i ( x ∗ x i ) + b ∗ = 0   ( 7 ) \sum_{i=1}^N\alpha_i^*y_i(x*x_i)+b^*=0\space(7) i=1Nαiyi(xxi)+b=0 (7)

  决策函数可以写成
f ( x ) = s i g n ( ∑ i = 1 N α i ∗ y i ( x ∗ x i ) + b ∗ )   ( 8 ) f(x)=sign(\sum_{i=1}^N\alpha_i^*y_i(x*x_i)+b^*) \space (8) f(x)=sign(i=1Nαiyi(xxi)+b) (8)

  由此可以看出,分类决策函数只依赖于输入x和训练样本输入的内积,式(8)称为线性可分支持向量机的对偶形式。





2. 动手实战

2.1. 项目案例:预测患疝气病的马的存活问题


项目概述
  我们先使用简单的数据集进行测试,数据集下载

可视化数据集

import matplotlib.pyplot as plt
import numpy as np

"""
函数说明:读取数据

Parameters:
    fileName - 文件名
Returns:
    dataMat - 数据矩阵
    labelMat - 数据标签
"""
def loadDataSet(fileName):
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():                                     #逐行读取,滤除空格等
        lineArr = line.strip().split('\t')
        dataMat.append([float(lineArr[0]), float(lineArr[1])])      #添加数据
        labelMat.append(float(lineArr[2]))                          #添加标签
    return dataMat,labelMat

"""
函数说明:数据可视化

Parameters:
    dataMat - 数据矩阵
    labelMat - 数据标签
Returns:
    无
"""
def showDataSet(dataMat, labelMat):
    data_plus = []                                  #正样本
    data_minus = []                                 #负样本
    for i in range(len(dataMat)):
        if labelMat[i] > 0:
            data_plus.append(dataMat[i])
        else:
            data_minus.append(dataMat[i])
    data_plus_np = np.array(data_plus)              #转换为numpy矩阵
    data_minus_np = np.array(data_minus)            #转换为numpy矩阵
    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1])   #正样本散点图
    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图
    plt.show()

if __name__ == '__main__':
    dataMat, labelMat = loadDataSet('testSet.txt')
    showDataSet(dataMat, labelMat)

  运行结果如下:
在这里插入图片描述



简化版SMO算法

from time import sleep
import matplotlib.pyplot as plt
import numpy as np
import random
import types

"""
函数说明:读取数据

Parameters:
    fileName - 文件名
Returns:
    dataMat - 数据矩阵
    labelMat - 数据标签
"""
def loadDataSet(fileName):
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():                                     #逐行读取,滤除空格等
        lineArr = line.strip().split('\t')
        dataMat.append([float(lineArr[0]), float(lineArr[1])])      #添加数据
        labelMat.append(float(lineArr[2]))                          #添加标签
    return dataMat,labelMat


"""
函数说明:随机选择alpha

Parameters:
    i - alpha
    m - alpha参数个数
Returns:
    j -
"""
def selectJrand(i, m):
    j = i                                 #选择一个不等于i的j
    while (j == i):
        j = int(random.uniform(0, m))
    return j

"""
函数说明:修剪alpha

Parameters:
    aj - alpha值
    H - alpha上限
    L - alpha下限
Returns:
    aj - alpah值
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Zhihu:
    https://www.zhihu.com/people/Jack--Cui/
Modify:
    2017-09-21
"""
def clipAlpha(aj,H,L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj

"""
函数说明:简化版SMO算法

Parameters:
    dataMatIn - 数据矩阵
    classLabels - 数据标签
    C - 松弛变量
    toler - 容错率
    maxIter - 最大迭代次数
Returns:
    无
"""
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    #转换为numpy的mat存储
    dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose()
    #初始化b参数,统计dataMatrix的维度
    b = 0; m,n = np.shape(dataMatrix)
    #初始化alpha参数,设为0
    alphas = np.mat(np.zeros((m,1)))
    #初始化迭代次数
    iter_num = 0
    #最多迭代matIter次
    while (iter_num < maxIter):
        alphaPairsChanged = 0
        for i in range(m):
            #步骤1:计算误差Ei
            fXi = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
            Ei = fXi - float(labelMat[i])
            #优化alpha,更设定一定的容错率。
            if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
                #随机选择另一个与alpha_i成对优化的alpha_j
                j = selectJrand(i,m)
                #步骤1:计算误差Ej
                fXj = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
                Ej = fXj - float(labelMat[j])
                #保存更新前的aplpha值,使用深拷贝
                alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
                #步骤2:计算上下界L和H
                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
                #步骤3:计算eta
                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
                #步骤4:更新alpha_j
                alphas[j] -= labelMat[j]*(Ei - Ej)/eta
                #步骤5:修剪alpha_j
                alphas[j] = clipAlpha(alphas[j],H,L)
                if (abs(alphas[j] - alphaJold) < 0.00001): print("alpha_j变化太小"); continue
                #步骤6:更新alpha_i
                alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])
                #步骤7:更新b_1和b_2
                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
                #步骤8:根据b_1和b_2更新b
                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("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num,i,alphaPairsChanged))
        #更新迭代次数
        if (alphaPairsChanged == 0): iter_num += 1
        else: iter_num = 0
        print("迭代次数: %d" % iter_num)
    return b,alphas

"""
函数说明:分类结果可视化

Parameters:
    dataMat - 数据矩阵
    w - 直线法向量
    b - 直线解决
Returns:
    无
"""
def showClassifer(dataMat, w, b):
    #绘制样本点
    data_plus = []                                  #正样本
    data_minus = []                                 #负样本
    for i in range(len(dataMat)):
        if labelMat[i] > 0:
            data_plus.append(dataMat[i])
        else:
            data_minus.append(dataMat[i])
    data_plus_np = np.array(data_plus)              #转换为numpy矩阵
    data_minus_np = np.array(data_minus)            #转换为numpy矩阵
    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7)   #正样本散点图
    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图
    #绘制直线
    x1 = max(dataMat)[0]
    x2 = min(dataMat)[0]
    a1, a2 = w
    b = float(b)
    a1 = float(a1[0])
    a2 = float(a2[0])
    y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2
    plt.plot([x1, x2], [y1, y2])
    #找出支持向量点
    for i, alpha in enumerate(alphas):
        if abs(alpha) > 0:
            x, y = dataMat[i]
            plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')
    plt.show()


"""
函数说明:计算w

Parameters:
    dataMat - 数据矩阵
    labelMat - 数据标签
    alphas - alphas值
Returns:
    无
"""
def get_w(dataMat, labelMat, alphas):
    alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)
    w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)
    return w.tolist()


if __name__ == '__main__':
    dataMat, labelMat = loadDataSet('testSet.txt')
    b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)
    w = get_w(dataMat, labelMat, alphas)
    showClassifer(dataMat, w, b)

  运行结果如下:
在这里插入图片描述在这里插入图片描述


参考资料

  • https://blog.csdn.net/c406495762/article/details/78072313
  • https://www.jianshu.com/p/59ed6e68703d
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页