机器学习算法感知机详解加代码

感知机

今天出去跑滴滴看到一个小伙子拿了一本李航的统计学习方法,于是回家又翻出了这本书打算从头到尾写博客介绍一遍各个算法的原理和代码。

感知机模型

感知机是一个二分类的线性分类模型,输入实例的特征向量,输出实例的类别,取+1,-1二值,对应于特征空间中将实例划分为正负两类的超平面,那么如何求得这个超平面,导入了基于误分类的实例的损失函数,使用梯度下降法求解损失函数最小化时的最优参数w和b,求得了感知机模型。
感知机函数:f(x)=sign(w·x+b)
其中x表示了实例的特征向量,w是权值向量,b为偏置,sign是符号函数当x大于等于0,就输出1,否则的话就输出-1,那么感知机函数就是如果wx+b大于等于0,f(x)就等于1,反之亦然。
前面说过,感知机是一个线性分类模型,而感知机函数中的wx+b就是我们要找的那条线,当上升到高维空间后,比如说现在我们的样本特征有三类,我们的超平面就不再是一条线了,而是一个平面,当上升到四维空间后,超平面就是一个同样能将四维空间划分为正负两类的东西。

感知机学习策略

为了找到我们的超平面的参数w和b,需要确定一个学习策略,就是定义损失函数,并且让他最小化,在感知机中损失函数是用误分类点到超平面的总距离来表示的,那么我们就需要一个特征空间中的一点x到超平面的距离公式。

书中并没有给出公式的推导过程,不过这个距离公式很好推导和理解,我们将超平面wx+b作为x轴,将整个图旋转,那么所有点到x轴的距离就变成了wx+b,下方的点到x轴的距离是|wx+b|,所有误分类的点到超平面的距离就是|wx+b|的总和,其中如果y(wx+b)>0则认为分类是正确的,否则是错误的,且y(wx+b)的值越大,分类结果的确信度也越大,反之也是,所以样本点(xi,yi)与超平面的函数间隔定义为
现在的情况是我们的目的是让函数间隔越大越好,函数间隔越大,代表我们对分类的结果非常确定,但是有一个问题存在,我们在同时成比的增加缩小w,b时,超平面却不发生改变,但是函数间隔却变化了,所以我们需要加上约束,就除上w的模长,这时w和b如果等比缩小,那么||w||也会等比缩小,就不会发生上述情况,这时,我们的间隔就变成了几何间隔

机器学习算法感知机详解加代码_第1张图片
上图在最后说不考虑除以w的模长,但是上文中我们分析了函数间隔的问题,这里为什么不考虑了呢,谷歌了一下,找到了一种解释,说感知机最终的目标是没有误分类的点,这样总距离和变成了0,w和b的值怎么变化就没有了影响,为了计算简单,使用了函数间隔。
机器学习算法感知机详解加代码_第2张图片
给出了损失函数的定义,求解w和b的最优解的方法采用了梯度下降方法,梯度下降法是求解机器学习算法的模型参数时最常用的方法之一,具体流程不再赘述,在代码环节给出了随机梯度下降的实现方法,至于书上的例题根据梯度下降法可逐步推出迭代过程。

感知机对偶形式

由于在算法开始时需要制定一个w和b的值,在对偶形式中,让w和b初值都为0,这样w和b最优值就变成了相对于0的增量,输出并给出了表示方式,也不再赘述,由于在迭代过程中需要多次计算xi*xj的值,所以就将值全部储存在了矩阵中,这个矩阵就是Gram矩阵,每次计算时候只需查一下矩阵,提高了计算效率,书上例题也可根据公式,逐步推出结果。

下面展示 感知机实现代码

import numpy as np
import pandas as pd

# 算法中的dataSet默认最后一列是标签

#标准化
def regularize(xMat):
    inMat=xMat.copy()
    inMeans=np.mean(inMat,axis=0)
    inVar=np.std(inMat,axis=0)
    inMat=(inMat-inMeans)/inVar
    return inMat

#随机梯度下降
def gradDescent(dataSet,eps=0.01,numIt=5000):
    dataSet=dataSet.sample(numIt,replace=True)
    dataSet.index=range(dataSet.shape[0])
    xMat=np.mat(dataSet.iloc[:,:-1].values)
    yMat=np.mat(dataSet.iloc[:,-1].values).T
    #xMat=regularize(xMat)
    #yMat=regularize(yMat)
    m,n=xMat.shape
    weights=np.zeros((n,1))
    for i in range(m):
        grad=xMat[i].T*(xMat[i]*weights-yMat[i])
        weights=weights-eps*grad
    return weights

#感知机
def perceptron(dataSet,eps=0.01,numIt=70000):
    dataSet=dataSet.sample(numIt,replace=True)
    dataSet.index=range(dataSet.shape[0])
    xMat=np.mat(dataSet.iloc[:,:-1].values)
    yMat=np.mat(dataSet.iloc[:,-1].values).T
    #xMat=regularize(xMat)
    #yMat=regularize(yMat)
    m,n=xMat.shape
    weights=np.zeros((n,1))
    b=0
    for i in range(m):
        if -1*yMat[i]*(xMat[i]*weights+b) >=0:
            weights=weights+eps*xMat[i].T*yMat[i]
            b=b+eps*yMat[i]
    return weights,b

#准确率
def model_test(dataset,weights,b,numIt=70000):
    dataSet=dataset.sample(numIt,replace=True)
    dataSet.index=range(dataSet.shape[0])
    xMat=np.mat(dataSet.iloc[:,:-1].values)
    yMat=np.mat(dataSet.iloc[:,-1].values).T
    #xMat=regularize(xMat)
    #yMat=regularize(yMat)
    m,n=xMat.shape
    L=0
    for i in range(m):
        result=-1*yMat[i]*(xMat[i]*weights+b)
        if result>=0:
            L+=1
    accruRate=1-(L/m)
    print('Acc:{:.3f}'.format(accruRate))

你可能感兴趣的:(机器学习)