机器学习之感知机模型(1),python底层代码实现

感知机是二分类线性模型,其输入为实例的特征向量,输出为实例的类别,取+1和-1值。感知机学习算法具有简单而易于实现的优点,分为原始形式和对偶形式。感知机由Rosenblatt于1957年提出,是神经网络和支持向量机的基础。


感知机(perceptron)

<font color=#999AAA


一、感知机模型

感知机是一种线性分类模型,属于判别模型。感知机模型的假设空间是定义在特征空间中的所有线性分类模型或线性分类器。
感知机有如下解释:线性方程 w ⋅ x + b = 0 w\cdot x+b=0 wx+b=0为特征空间中的一个超平面, w w w是超平面的法向量,b是超平面的截距。此平面将特征空间分为两个部分,对应正负两个类别。所以,该超平面称为分离超平面。感知机算法的目标是学习最佳的 w w w和b,使得错误分类的点数最少。

二、学习策略

1.损失函数

假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练集正类点和负类点完全正确分开的分离超平面。为了找出这样得超平面,需要确定一个合适的损失函数并将损失函数极小化。首先想到的是将误分类点数作为损失函数,但是这样的损失函数不是参数 w w w和b的连续可导函数,不易优化。所以选择损失函数为误分类点到超平面的总距离。
中学就学过点线间的距离公式: l = ∣ a ⋅ x + b ⋅ y + c ∣ a 2 + b 2 l=\frac{\left| a\cdot x+b\cdot y+c \right|}{\sqrt{a^2+b^2}} l=a2+b2 ax+by+c
所以对于特征空间 R n R^n Rn中的任意一点到超平面的距离为:
∣ w ⋅ x + b ∣ ∥ w ∥ 2 \frac{\left| w\cdot x+b \right|}{\left\| w \right\| _2} w2wx+b
其中, ∥ w ∥ 2 \left\| w \right\| _2 w2为向量 w w w的l2范数,即欧式距离。而对于误分类 点来说,
− y i ∣ w ⋅ x i + b ∣ > 0 -y_i\left| w\cdot x_i+b \right|>0 yiwxi+b>0
因为感知机的特征空间中的正负类点满足: y i = { + 1 , w ⋅ x i + b > 0 − 1 , w ⋅ x i + b < 0 y_i=\begin{cases} +1,w\cdot x_i+b>0\\ -1,w\cdot x_i+b<0\\ \end{cases} yi={+1,wxi+b>01,wxi+b<0
所以,对于所有误分类点到超平面的距离为:
∑ i = 1    m ( − 1 ∥ w ∥ 2 y i ( w ⋅ x i + b ) ) = − 1 ∥ w ∥ 2 ∑ i = 1    m ( y i ( w ⋅ x i + b ) ) \sum_{i=1}^{\,\,m}{\left( -\frac{1}{\left\| w \right\| _2}y_i\left( w\cdot x_i+b \right) \right)} \\ =-\frac{1}{\left\| w \right\| _2}\sum_{i=1}^{\,\,m}{\left( y_i\left( w\cdot x_i+b \right) \right)} i=1m(w21yi(wxi+b))=w21i=1m(yi(wxi+b))
这里不考虑 1 ∥ w ∥ 2 \frac{1}{\left\| w \right\| _2} w21,所以最终的损失函数为:
L ( w , b ) = − ∑ i = 1    m ( y i ( w ⋅ x i + b ) ) L\left( w,b \right) =-\sum_{i=1}^{\,\,m}{\left( y_i\left( w\cdot x_i+b \right) \right)} L(w,b)=i=1m(yi(wxi+b))
该函数针对误分类点,所以当无误分类点是,损失函数值为0。误分类点越少,误分类点离超平面越近,损失函数值越小。

2 优化算法

随机梯度下降算法

随机梯度下降算法的优化过程是一次随机选取一个误分类点使其梯度下降。假设误分类点集合M是固定的,那么损失函数的梯度为
∇ w L ( w , b ) = − ∑ i = 1    m y i x i ∇ b L ( w , b ) = − ∑ i = 1    m y i \nabla _wL\left( w,b \right) =-\sum_{i=1}^{\,\,m}{y_ix_i} \\ \nabla _bL\left( w,b \right) =-\sum_{i=1}^{\,\,m}{y_i} wL(w,b)=i=1myixibL(w,b)=i=1myi
随机选取一个误分类点,对w和b更新,
w = w + l r ∗ y i x i b = b + l r ∗ y i w=w+lr*y_ix_i \\ b=b+lr*y_i w=w+lryixib=b+lryi
其中,lr为学习率


三、代码实现

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs

from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt

np.random.seed(3)
X, Y = make_blobs(n_samples=200,n_features=2,centers=2)
for i in range(len(Y)):##将类别标签设置为1和-1
    if Y[i]==0:
        Y[i]=-1
x_train,x_test,y_train,y_test = train_test_split(X,Y,test_size=0.2)
class  perceptron:#感知机
    def __init__(self):
        self.train_loss=[]
        self.val_loss=[]
    def __loss_function(self,x,y):##损失函数,为所有错误类点的函数间隔的和的相反数
        mis_classes=y*np.dot(self._theta,x.T)*y#所有点的函数间隔
        loss=0
        for mis_class in mis_classes:#选出误分类点的函数间隔,计算loss值,如无误分类点,loss为0
            if mis_class<=0: 
                loss=loss+mis_class
        return -loss
    def gradient(self,optimizer):#梯度下降法求解
        if optimizer=="sgd":#随机梯度下降法
            for j in range(self.epochs):
                for i in range(len(self._x_train)):
                    if self._y_train[i]*np.dot(self._theta,self._x_train[i].T)<=0: 
                        self._theta=self._theta+self.learn_rate*self._y_train[i]*self._x_train[i]
                        self.train_loss.append(self.__loss_function(self._x_train,self._y_train))#参数更新后计算损失loss
                     
        elif optimizer=="bgd":#批量梯度下降算法
            pass
        elif optimizer=="mbgd":#小批量梯度下降
            pass
    #训练函数,形参为x_train,y_train,学习率,迭代次数,梯度下降算法选择,后三为默认传参
    def train(self,x_train,y_train,learn_rate=0.01,epochs=10,optimizer="sgd"):
        self.learn_rate=learn_rate
        self.epochs=epochs
        self.optimizer=optimizer
        self._x_train=np.append(x_train, np.ones((1,x_train.shape[0])).T,axis=1)
        #self._x_train=np.insert(self._x_train,0,1,axis=1)##扩展x_train,表示常数项
        self._y_train=y_train
        self._theta=np.random.rand(self._x_train.shape[1]) #theta初始化
        self.train_loss.append(self.__loss_function(self._x_train,self._y_train))
        self.gradient(optimizer)
    #预测函数
    def predict(self,x_test):
        x_test=np.append(x_test, np.ones((1,x_test.shape[0])).T,axis=1)##扩展x_test,表示常数项
        y_test=np.zeros((len(x_test),1))
        #x_test=p.insert(self._x_test,0,1,axis=1)
        for i in range(len(x_test)):
            if(np.dot(self._theta.T,x_test[i])>=0):
                y_test[i]=1
            else:
                y_test[i]=-1
        return y_test
if __name__=="__main__":
    model=perceptron()
    model.train(x_train,y_train,0.1,20,"sgd")
    y_pred=model.predict(x_test)
    print(confusion_matrix(y_pred,y_test))
    plt.scatter(x_test[:,0],x_test[:,1],marker='x',c=y_test)
    plt.scatter(x_train[:,0],x_train[:,1],c=y_train)
    plt.plot(x_test[:,0],-model._theta[0]/model._theta[1]*x_test[:,0]-model._theta[2]/model._theta[1])

在这里插入图片描述
可以看到,决策超平面将正负两类以完全分开。但是,由于感知机模型的目标为使误分类点的个数最小,所以超平面不唯一,不同顺序的误分类点集,得到的 超平面可能不同,如下图所示:
在这里插入图片描述

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值