统计机器学习--感知机

今天开始, 要开始学李航的统计机器学习了,虽然现在都是深度学习横着走,但基础的东西还是要学起来的,一直想学这本书,因为太多别的事情,一直在拖,今天决定不再拖延,在五一之前都专心学李航这本书,把该掌握的都掌握了。(立下一个不可能实现的flag)

本博客不会详细介绍书里的内容,主要作为我个人的笔记记录,(毕竟有书,我没必要把书抄一遍)。另外会贴大佬的代码并进行必要的讲解,不过终究是大佬的代码,这次学习不打算自己复现模型,以快速学习为主要,部分深入学习的形式来学这本书。

我不会很细致地讲,因为我没有这个水平。

一. 感知机模型

感知机的公式为:f(x) = sign(w·x + b)

其中:w,b:为模型的训练参数

x:为模型的输入

f(x):为模型的输出(也就是预测结果,注意这里不是正确答案,而是预测答案,我刚开始学就没分清楚这个,为我自己标注)。

sign(x):为符号函数(选择函数):sign(x) = +1 if x>=0, -1 if x < 0。(emmm,这表达式好像有什么不对的样子)

二. 感知机学习策略

为了方便起见,我们认为我们的目标是进行二分类,并且数据是线性可分的,所谓的线性可分,就是数据样本可以被一条直线或者一个超平面(注意是平的)划分成两部分,一部分是正样本,一部分是负样本(正负只是说法上的习惯,并不是说真的一定是正负的样本,所以我为什么这么啰嗦)。

那么,这个超平面S是什么呢? 

书里给出的公式是 W·X + B = 0。

这里有一个需要注意的点,刚开始学机器学习的时候,总是会把习惯上的y = kx + b和模型中的y联系在一起,然而,因为我当时这么联系,总是会在脑海中构建坐标系的时候,把y也加进去,导致越学越乱,虽然加进去是对的,但是大多数教材都习惯性不建立这个y轴,毕竟在分类任务中,y的取值很有限,没必要为了y值建立一条坐标轴。所以,我们建立一个没有y轴的坐标系,坐标轴都有X(x1, x2, x3, .. , xn)组成,也就是特征组成。

那么到这里就能清楚了,这个一个在由坐标轴X(x1, x2, x3, .., xn)组成的坐标系中的一个超平面,其中,W(w1, w2, w3, .. , wn),为每个特征的系数(在二维平面上我们称之为斜率,没错,是一样的),B(b1, b2, b3, .. , bn)则是每个坐标系上的截距。其实就是因为变成了向量形式,所以稍微需要转转弯才能想明白(像我就需要转好多好多弯,才想明白)。

OK!有了超平面的公式了,现在的任务就是确定超平面,那么怎么确定超平面呢? 

我们首先明确,我们设置这个超平面是为了什么?没错,正确划分数据样本,那么只要能正确划分数据样本,这个超平面就是我们想要的超平面,那么怎么评判这个超平面正确划分了数据样本呢?

这个时候就由大名鼎鼎的损失函数登场了,书中选择的损失函数是统计每个误分类点到超平面S的距离。

其中点到超平面的距离公式为:\frac{1}{||W||}|w\cdot ·x + b|

误分类点xi到超平面的距离为-\frac{1}{||W||}y_{i}|w\cdot ·x_{i} + b|

由于损失函数是所有误分类点到超平面的距离的和,对应的公式为:-\frac{1}{||W||} \sum_{x_{i}\epsilon M}y_{i}|w\cdot ·x_{i} + b|

其中M为误分类点集合。

三. 感知机学习算法

学习算法也就是训练模型的方法,书中采用梯度下降的方式最小化损失函数(也就是训练模型)。

梯度下降具体怎么工作的,学过高数的同学肯定都知道,凸函数只有一个极值,且这个极值为最值。为了便于理解,我们只讨论二维平面上的凸函数,且这个极值就是极小值(最小值),当然,极大值也是可以的,只是换个方向,没有太多变化。

那么梯度下降具体怎么工作的呢?(这里不打算讨论细致,感兴趣的同学直接查阅梯度下降),其实梯度下降就是一个找到极值点(损失函数的极值点)的操作,通过计算损失函数关于每个wi的导数,来更新每个wi,bi同理。至于为什么可以这么做呢,因为这样可以让损失变小,更具体的就不讨论了,因为我懒。

更多的细节请参考书(书籍的名字和出版会在最后写明)。

感知机学习算法的原始形式:(其他形式不讨论)步骤如下:

1. 选取初值x0,b0。

2. 在训练集中选取数据(xi, yi)。

3. 如果yi(w·x+b)<=0

         w <- w + \etaxiyi

         b <- b + \etayi

4. 转至2,直至训练集中没有误分类点。

四. 代码

# 数据线性可分,二分类数据
# 此处为一元一次线性方程
class Model:
    def __init__(self):
        self.w = np.ones(len(data[0])-1, dtype=np.float32)
        self.b = 0
        self.l_rate = 0.1
        # self.data = data
    
    def sign(self, x, w, b):
        y = np.dot(x, w) + b
        return y
    
    # 随机梯度下降法
    def fit(self, X_train, y_train):
        is_wrong = False
        while not is_wrong:
            wrong_count = 0
            for d in range(len(X_train)):
                X = X_train[d]
                y = y_train[d]
                if y * self.sign(X, self.w, self.b) <= 0:
                    self.w = self.w + self.l_rate*np.dot(y, X)
                    self.b = self.b + self.l_rate*y
                    wrong_count += 1
            if wrong_count == 0:
                is_wrong = True
        return 'Perceptron Model!'
        
    def score(self):
        pass

perceptron = Model()
perceptron.fit(X, y)

更多的代码请参考第五节参考中给出的github连接。

可以看到,Model类中,有初始化init,符号函数sign,训练函数fit

其中inti为初始化参数W,B,还有设置学习速率l_rate(也就是梯度下降的速度)。

符号函数sign,这个符号函数是假的,由于对于后面的计算,只需要判定结果是否为非负或者负即可,是不是符号函数并不影响。(大佬,我帮你把场子圆回来了)。

训练函数fit,由于这个比较重要,我重点讲一下,(敲黑板!!)。其中

wrong_count:表示模型误分类的个数。

 if y * self.sign(X, self.w, self.b) <= 0: 为判断当前样本点是否会被误分类,如果满足条件,则为误分类,则进行梯度下降并增加误分类个数wrong_count。(这里是<=0而不是>0是因为,他没有加负号,所以没有问题,自以为你们会在这里有疑惑,因为跟上面不一样)。

self.w = self.w + self.l_rate*np.dot(y, X)和self.b = self.b + self.l_rate*y:对w,b进行更新,也就是梯度下降。这个公式与我们第三节3对应。注意这里的np.dot是矩阵乘法,不是点乘。所以np.dot(y, X)结果是一个矩阵。

fit的最后就是一个误分类样本都没有了,不过这个太理想了,一般会设置阈值或者是训练次数来提前结束训练。

五. 参考

1.《统计机器学习》 -- 李航,清华大学出版社。(印次:2016年11月第16次印刷)。

2. github: https://github.com/wzyonggege/statistical-learning-method/blob/master/Perceptron/Iris_perceptron.ipynb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值