统计学习笔记1:感知机学习算法的原始形式及其python代码实现

1感知机学习算法原理

1.1算法应用背景

        假设训练数据集是线性可分的,感知机学习其实可以算是一个二分类问题,因为其输出Y的取值只能在1,-1之间取得,所以感知机的目标就是找到完全正确将训练集分为正实例以及负实例的超平面S,可以表示为

w\cdot x+b=0

      所以我们的目标就是通过不断迭代找到w,b直至完全正确分类。

1.2算法数学原理

     为了衡量一个超平面对于训练集分类的正确程度,引入损失函数L\left( w,b \right)来表示学习效果的好与坏。可以选择所有误分类点到超平面的距离和作为损失函数。首先写出输入空间中任意一点x_0到超平面S的距离是

\frac{1}{\left\| w \right\|}\left| w\cdot x_0+b \right|

     其中\left\| w \right\| =\sqrt{\sum\nolimits_i^n{\left( w_i \right) ^2}}称为w的L2范数。对于误分类的点有-y_i\left( w\cdot x_i+b \right) >0,并且\left\| w \right\|为一常数,则损失函数L\left( w,b \right)可以写为如下形式:

L\left( w,b \right) =-\sum_{x_i\in M}{y_i\left( w\cdot x_i+b \right)}

     M为所有误分类点的集合。则感知机学习算法就可以看成求解损失函数最小化的最优化问题,最优化的方法采用随机梯度下降法,大致可以分为如下两个步骤

     1.随机选取一个误分类点使其梯度下降,则L\left( w,b \right)的梯度由

\nabla _wL\left( w,b \right) =\frac{\partial L\left( w,b \right)}{\partial w}=-\sum_{x_i\in M}{y_ix_i}

\nabla _bL\left( w,b \right) =\frac{\partial L\left( w,b \right)}{\partial b}=-\sum_{x_i\in M}{y_i}

    表示

    2.对w,b进行更新

w\gets w+\eta y_ix_i

b\gets w+\eta y_i

   其中\eta \left( 0<\eta \leqslant 1 \right)为学习率,这样经过不断迭代就能使损失函数L\left( w,b \right)不断减小,直到为0。

2感知机学习算法python实现

2.1 问题描述

       问题来源于李航《统计学习方法》中的例题。有一训练数据集,其正实例点是x_1=\left( 3,3 \right)x_2=\left( 4,3 \right),负实例点是x_3=\left( 1,1 \right),使用感知机学习算法的原始形式求感知机模型f\left( x \right) =sign\left( w\cdot x+b \right)。这里w=\left( w_1,w_2 \right) ,x=\left( x_1,x_2 \right)。本文使用python来实现。

2.2数据导入

       在python中导入numpy,用数组的形式将数据导入,方便后续处理

def loadData():
    data=np.array([[3,3],[4,3],[1,1]]) #导入数据
    labels=np.array([1,1,-1])          #导入标签

    x0=np.ones((1,len(labels)))       #bias偏置
    data=np.insert(data,0,values=x0,axis=1) #按列插入1,作为偏置
    return data,labels

      其中把偏置b认为是特殊的特征,取x_0=1,可得b=w_0\cdot x_0=w_0,则后续b的更新可以合并入w一起更新,简化了代码。通过以上操作,最终得到的data为3×3的矩阵

[[1 3 3]
 [1 4 3]
 [1 1 1]]

2.3初始化

     新建一个类并命名为PLA,对其进行初始化代码如下

class PLA:
    def __init__(self,data,labels,a=1): #初始化
        self.data=data                  #实例的数据
        self.labels=labels              #实例的标签
        self.a=a                        #a为学习率
        self.w=np.zeros((data.shape[1],1)) #初始权重为0
        self.numdata=data.shape[0]         #样本数
        self.numfeatures=data.shape[1]    #特征数

    其中所有的权重初始化为0,学习率a初始化为1,将偏置b看作特殊的特征,故此处numfeatures应该为3而不是2。

2.4写sign函数

      通过判断-y_i\left( w\cdot x_i+b \right)的符号即可说明某样本点是否是误分类点,所以需要自行写一个sign函数来判断符号,代码如下

    def sign(self,data_i,labels_i):
        tmp=int(np.dot(data_i,self.w))*labels_i #以yi*(w*xi+b)的符号来判别是否正确分类
        if tmp>0:
            return 1
        else:
            return -1

     其中np.dot用于两个矩阵进行点乘操作。

2.5更新参数

     运用梯度下降法更新参数,由于上文将偏置b看作特殊的特征,故此处b和w的更新公式便统一成了一个,代码如下

    def update(self,data_i,labels_i):
        self.w=self.w+(self.a*labels_i*data_i).reshape(self.w.shape)

2.6 训练模型

     将样本点代入模型进行迭代运算,直至不再出现误分类点,即感知机模型训练完成。

    def trainPLA(self):
        bMisClassify=True
        while bMisClassify:
            mMisClassifyNum=0
            for i in range(self.numdata):
                if self.sign(self.data[i,:],self.labels[i])==-1:
                    mMisClassifyNum+=1
                    self.update(self.data[i,:],self.labels[i])
            if mMisClassifyNum==0:
                bMisClassify=False
        print('The PLA Training has finished! The w is :\n',self.w)
        return self.w

    最后输出的应该是一个3×1的权重矩阵w。

2.7可视化

    在python中导入matplotlib.pyplot来进行模型可视化,新建一个Plot类专门用于画图。

class Plot:
    def __init__(self,x,y,w):
        self.w=w
        plt.figure(1)
        plt.title('Perceptron Learning Algorithm')
        plt.xlabel('X0')
        plt.ylabel('X1')

        xdata=np.arange(0,7)                  #x轴范围
        ydata=-(w[0][0]+w[1][0]*xdata)/w[2][0]
        plt.plot(xdata,ydata,c='r')

        for i in range(len(y)):
            if y[i]==1:
                plt.scatter(x[i,1],x[i,2],c='g',marker='o')
            else:
                plt.scatter(x[i,1],x[i,2],c='b',marker='x')
        plt.savefig('Blog1.png')
        plt.show()

     其中w[0][0]就是b,所以在此题中超平面S的形式应为w_2y+w_1x+w_0,故y=-\left( w_1x+w_0 \right) /w_2

2.8整体代码

     添加主程序后,整体代码如下

import numpy as np
import matplotlib.pyplot as plt

def loadData():
    data=np.array([[3,3],[4,3],[1,1]]) #导入数据
    labels=np.array([1,1,-1])          #导入标签

    x0=np.ones((1,len(labels)))       #bias偏置
    data=np.insert(data,0,values=x0,axis=1) #按列插入1,作为偏置
    return data,labels

class PLA:
    def __init__(self,data,labels,a=1): #初始化
        self.data=data                  #实例的数据
        self.labels=labels              #实例的标签
        self.a=a                        #a为学习率
        self.w=np.zeros((data.shape[1],1)) #初始权重为0
        self.numdata=data.shape[0]         #样本数
        self.numfeatures=data.shape[1]    #特征数

    def sign(self,data_i,labels_i):
        tmp=int(np.dot(data_i,self.w))*labels_i #以yi*(w*xi+b)的符号来判别是否正确分类
        if tmp>0:
            return 1
        else:
            return -1

    def update(self,data_i,labels_i):
        self.w=self.w+(self.a*labels_i*data_i).reshape(self.w.shape)

    def trainPLA(self):
        bMisClassify=True
        while bMisClassify:
            mMisClassifyNum=0
            for i in range(self.numdata):
                if self.sign(self.data[i,:],self.labels[i])==-1:
                    mMisClassifyNum+=1
                    self.update(self.data[i,:],self.labels[i])
            if mMisClassifyNum==0:
                bMisClassify=False
        print('The PLA Training has finished! The w is :\n',self.w)
        return self.w

class Plot:
    def __init__(self,x,y,w):
        self.w=w
        plt.figure(1)
        plt.title('Perceptron Learning Algorithm')
        plt.xlabel('X0')
        plt.ylabel('X1')

        xdata=np.arange(0,7)                  #x轴范围
        ydata=-(w[0][0]+w[1][0]*xdata)/w[2][0]
        plt.plot(xdata,ydata,c='r')

        for i in range(len(y)):
            if y[i]==1:
                plt.scatter(x[i,1],x[i,2],c='g',marker='o')
            else:
                plt.scatter(x[i,1],x[i,2],c='b',marker='x')
        plt.savefig('Blog1.png')
        plt.show()

if __name__=='__main__':
    data,labels=loadData()
    print(data)
    myPLA=PLA(data,labels)
    weights=myPLA.trainPLA()
    Plot(data,labels,weights)

     运行之后输出权重矩阵w为

The PLA Training has finished! The w is :
 [[-3.]
 [ 1.]
 [ 1.]]

     绘制出的分离超平面如下图

    可见与书中所得结果一致,成功将正负实例点进行了分离,具体迭代过程见书中下表。

3 学习心得

       大四终于有时间系统学习机器学习,翻了几页西瓜书,感觉其中涉及的推导过于简洁,实在令人高山仰止。求助网友后开始学习李航老师的《统计学习方法》,发现其中无论是概念还是推导都十分地详尽,不知不觉就学习完了一章,手推完公式后便赶紧用python将例题复现一遍以加深记忆。第一次写博客,就当是在学习机器学习过程中随手记录下来的笔记,有不正当之处恳请各位包容并指出。研路漫漫,唯学习不可懈怠,与诸君共勉!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值