机器学习系列(一)感知器分类算法

本文详细介绍了感知器算法的工作原理,包括权重初始化、激活函数、权重更新步骤以及适用范围。通过实例展示了如何更新权重向量,并解释了线性可分数据对感知器算法的重要性。此外,还提供了感知器类的Python实现,以及训练数据的加载和预处理方法,为实际应用感知器模型奠定了基础。

分类算法有两种类型:感知器和适应性线性神经元

神经元的数学表示

w=[w1w2...wm],x=[x1x2...xm] w=\begin{bmatrix} w_1 \\ w_2 \\ ... \\ w_m \\ \end{bmatrix} , x=\begin{bmatrix} x_1 \\ x_2 \\ ... \\ x_m\\ \end{bmatrix}w=w1w2...wm,x=x1x2...xm
z=w1x1+w2x2+⋅⋅⋅+wmxm z=w_1x_1 + w_2x_2 + ···+w_mx_mz=w1x1+w2x2++wmxm
其中w为权重,x为训练样本

感知机的训练步骤

  1. 把权重向量初始化为0,或把每个分向量初始化为[0,1]间任意小数
  2. 把训练样本输入感知机,得到分类结果(-1或1)
  3. 根据分类结果更新权重向量

激活函数

为了计算方便我们添加w0x0w_0x_0w0x0, 其中w0=−θ,x0=1w_0=-\theta,x_0=1w0=θx0=1
z=w0x0+w1x1+...+wmxm=wTx,ϕ(z)={1if z>0−1,otherwise z=w_0x_0 + w_1x_1+...+w_mx_m = w^Tx , \phi(z)=\begin{cases} 1 & \text {if z>0} \\ -1, & \text{otherwise} \end{cases} z=w0x0+w1x1+...+wmxm=wTx,ϕ(z)={11,if z>0otherwise
这样,当z>0z>0z>0时,ϕ(z)=1\phi(z)=1ϕ(z)=1,当z<0z<0z<0时,ϕ(z)=−1\phi(z)=-1ϕ(z)=1.

权重的更新算法

  • w(j)=w(j)+Δw(j)w(j)=w(j)+\Delta w(j)w(j)=w(j)+Δw(j)
  • Δw(j)=η∗(y−y′)∗x(j)\Delta w(j)=\eta*(y-y')*x(j)Δw(j)=η(yy)x(j) : y表示x(j)的正确分类,y’表示感知机算出来的分类,x(j)表示训练样本。可以看出来如果感知器的分类结果y′y'y与正确分类yyy相同时,那么可以得到Δw(j)=0\Delta w(j)=0Δw(j)=0,也就可以得到w(j)=0w(j)=0w(j)=0,也就是说如果感知器可以正确对数据样本进行正确分类,那么对权重w(j)w(j)w(j)就不需要进行调整;只有感知器得到了错误的分类结果之后,出需要调整权重向量w(j)w(j)w(j)
  • η\etaη 表示学习率是[0,1]之间的一个小数,一般有使用者自己设置。通过反复运行模型,人为根据经验调整学习率η\etaη,使得模型训练结果越来越好。
  • w(0)=0,Δw(0)=η∗(y−y′)w(0)=0, \Delta w(0)=\eta*(y-y')w(0)=0,Δw(0)=η(yy)阈值的更新

举例说明如何更新权重

假设

  1. 权重向量初始化为:w=[0,0,0]w=[0,0, 0]w=[0,0,0]
  2. 训练样本的值:x=[1,2,3]x=[1,2,3]x=[1,2,3]
  3. 学习率:η=0.3\eta=0.3η=0.3
  4. 这个样本的正确分类y=1
  5. 感知器算出来的分类是y’=-1

调整权重向量Δw(0)=0.3∗(1−(−1))∗x(0)=0.3∗2∗1=0.6\Delta w(0)=0.3*(1-(-1))*x(0)=0.3*2*1=0.6Δw(0)=0.3(1(1))x(0)=0.321=0.6w(0)=w(0)+Δw(0)=0.6w(0) = w(0)+\Delta w(0)=0.6w(0)=w(0)+Δw(0)=0.6,则权重的第一个分量更新为0.6,即w=[0.6,0,0]w=[0.6,0,0]w=[0.6,0,0]

同理,Δw(1)=0.3∗(1−(−1))∗x(1)=0.3∗2∗2=1.2\Delta w(1)=0.3*(1-(-1))*x(1)=0.3*2*2=1.2Δw(1)=0.3(1(1))x(1)=0.322=1.2,则更新权重的第二个分量为w(1)=w(1)+Δw(1)=1.2w(1)=w(1)+\Delta w(1)=1.2w(1)=w(1)+Δw(1)=1.2

同理,Δw(2)=0.3∗(1−(−1)∗x(2))=0.3∗2∗3=1.8\Delta w(2)=0.3*(1-(-1)*x(2))=0.3*2*3=1.8Δw(2)=0.3(1(1)x(2))=0.323=1.8,则更新权重的第三个分量为w(2)=w(2)+Δw(2)=1.8w(2)=w(2)+\Delta w(2)=1.8w(2)=w(2)+Δw(2)=1.8

最终可以得到更新后的权重向量为w=[0.6,1.2,1.8]w=[0.6, 1.2, 1.8]w=[0.6,1.2,1.8]

这样就可以再次将新的训练样本输入到模型中,根据分类结果走相同的步骤继续改进权重向量。

感知器算法的适用范围

在这里插入图片描述
必须要满足上图中第一个图中的情况,也就是预测的数据可以现行分割,感知器的训练目标就是要找出这条线。而后面两个情况,是无法进行线性可分的,不适用于感知器算法进行分类。

代码实现

定义感知器类

import numpy as np

class Perceptron(object):
    """
    eta: 学习率
    n_iter: 权重向量的训练次数
    w_: 神经分叉权重向量
    errors_: 用于记录神经元判断出错次数
    """
    def __init__(self, eta = 0.01, n_iter = 10):
        self.eta = eta
        self.n_iter = n_iter
        pass
    
    def fit(self, X, y):
        """
        输入训练数据,培训神经元,X表示输入样本, y对应样本的正确分类
        X: shape[n_samples, n_features]
        n_samples:表示有多少个训练样本数量
        n_features: 表示有多少个属性
        例如:X: [[1,2,3], [4,5,6]] => n_samples=2;n_features=3

        y: [1, -1]表示第一个向量的分类是1, 第二个向量的分类是-1
        """

        """
        首先初始化权重为0
        加一是因为激活函数w0,也就是阈值,这样就只用判断输出结果是否大于0就可以了
        """
        self.w_ = np.zero(1 + X.shape[1])
        self.errors_ = []

        """
		只要出现错误分类,那么反复训练这个样本,次数是n_iter
		"""
        for _ in range(self.n_iter): 
            errors = 0
            """
            X:[[1,2,3], [4,5,6]]
            y:[1, -1]

            zip(X, y) => [[1,2,3,1], [4,5,6-1]]
            """
            for xi, target in zip(X,y):
                """
                update = η * (y-y')
                """
                update = self.eta * (target - self.predict(xi))
                """
                xi 是一个向量, 例如[1,2,3], target表示1
                update 是一个常量
                update*xi 等价于 [Δw(1) = X[1]*update, Δw(2) = X[2]*update, Δw(3) = X[3]*update]
                """
                # w_[1:]表示w忽略第0个元素,从第一个元素开始往后
                self.w_[1:] += update * xi
                self.w_[0] += update * 1
                errors += int(update != 0.0)
                self.errors_.append(errors)
            pass
        pass
            
    def net_input(self, X):
        """
        z = W0*1 + W1*X1 + W2*X2+ ...+ Wn*Xn
        """
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def predict(self, X):
        """
        如果self.net_input(X) >= 0.0返回1, 否则返回-1
        """
        return np.where(self.net_input(X) >= 0.0 , 1, -1)

目前虽然有了感知器的分类算法,但是还没有运行起来,下面将如何使用这个感知器分类算法,然后将训练样本输入到模型中,最后进行预测数据。

介绍训练数据

有了基本模型后,要做的就是要把大量的数据,输入至模型中,让模型通过对大量数据的观察,总结出数据中隐含的某种规律,根据数据特点不断调节模型中神经元权重数值,当神经元的权重数值调节到合适的范围之内后,就可以利用训练后的模型对新的数据进行预测分类。
首先需要先介绍训练数据的数据结构。训练数据内容如下:
在这里插入图片描述
使用pandas工具,来读取数据,可以很容易的进行抽取数据。
首先安装pandas:pip install pandas -i https://pypi.douban.com/simple

import pandas as pd

file="./iris.csv"
df = pd.read_csv(file, header=None)
print(df.head())

结果输出如下:
在这里插入图片描述
可视化展示这个数据,使用matplotlib工具进行展示。

import matplotlib.pyplot as plt
import numpy as np
from test3 import df

# 将df中0到100行的数据的第四列赋值给y向量 
y = df.loc[0:100, 4].values
# 将Iris-setosa转为-1,其余转为1
y = np.where(y == 'Iris-setosa', -1, 1)
# print(y)
# 将df0到100行的数据的第0列和第2列抽取出来,赋值给x向量
X = df.iloc[0:100, [0, 2]].values
# print(X)
# 将X向量的钱50条数据的第0列作为x轴,第1列作为y轴坐标,画在二维坐标轴,画出来的点是红色的'o',
plt.scatter(X[:50, 0], X[:50, 1], color = 'red', marker='o', label='setosa')
plt.scatter(X[50:100, 0], X[50:100, 1], color = 'blue', marker='x', label='versicolor')
plt.xlabel('花瓣长度')
plt.ylabel('花径长度')
plt.legend(loc='upper left')
# 下面两行解决乱码问题
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False

plt.show()

在这里插入图片描述
可以看出来这两类数据可以线性分割开。

一步一步调试

初始化eta=0.1, w=[0 0 0]

5.1,1.4,target=-1, self.net_input(x)=W0*1+W1*5.1+W2*1.4=0,self.predict(xi)=1,update=eta*(target-self.predict(xi))=0.1*(-2)=-0.2,errors=1,W=[1*(-0.2)5.1*(-0.2)1.4*(-0.2)]=[-0.2 -1.02 -0.28]
4.9,1.4,target=-1, self.net_input(x)=W0*1+W1*4.9+W2*1.4=-0.2*1+(-1.02)*4.9+(-0.28)*1.4=-0.3918432<0,self.predict(xi)=-1,update=eta*(target-self.predict(xi))=0.1*0=0,errors=1,W=[-0.2+1*0-1.02+4.9*0-0.28+1.4*0]=[-0.2 -1.02 -0.28]
4.7,1.3,target=-1, self.net_input(x)=W0*1+W1*4.7+W2*1.3=-0.2+(-4.794)+(-0.364)<0,self.predict(xi)=-1,update=0,errors=1,W=[-0.2 -1.02 -0.28]
5.4,1.7,target=-1,self.net_input(x)<0,self.predict(xi)=-1,update=0,errors=1,W=[-0.2 -1.02 -0.28]
7,4.7,target=1,self.net_input(x)<0,self.predict(xi)=-1,update=0.2,errors=2,W=[(-0.2)+(0.2*1) (-1.02)+(0.2*7) (-0.28)+(0.2*4.7)]=[0 0.38 0.66]
  1. 首先得到样本数据和分类标签target
  2. 然后计算预测标签的值predict
  3. 更新权重W=eta*(target-predict), 将上一次的权重W进行累加w(j)+Δw(j)
  4. 以此类推
1. 感知器算法 感知器算法是通过训练模式的迭代和学习算法,产生线性可分的模式判别函数。感知器算法就是通过对训练模式样本集的“学习”得出判别函数的系数解。在本次实验中,我们主要是采用硬限幅函数进行分类感知器的训练算法如下: 设输入矢量 , 加权矢量 ,则神经元 的输出可通过下式来计算 (1) 这里对于训练结束我们判断的依据是实际输出值与理想预期值之间误差的均方值最小。定义 它的均方值记作 ,令 , 则可以推出 (2) 可证存在最佳的加权矢量 ,使 达到最小。解得 (3) 式(3)给出了求最佳加权矢量的方法,但是需要做大量的统计计算,并且需要解决高阶矩阵求逆的问题,这些都是非常困难的。于是我们给出种递推求解的方法: 在给定初始权值后,以这种方法可以得到递推公式: (4) 用这种方法虽然可以保证求得严格的最佳解,且避开了矩阵求逆的困难,但学习过程中的每步仍需完成大量的统计计算。 2.BP算法 由于硬限幅函数是非可微函数,不能实现多层神经网络的种有效的LMS学习算法。而BP算法中所用到的是Sigmoid型函数,它既具有完成分类所需的非线性特性,又具有实现LMS算法所需的可微特性。采用S型函数的神经元的输入和输出之间的关系为: (5) 采用了S型函数就可将用于单神经元的LMS学习算法适当推广,得到种适用于前向多层神经网络的有效学习算法。 我们现在研究个采用S型函数的前向三层神经网络来说明其原理。 对于训练样本p,它的输入是N维矢量X,X= ,网络的第,二,三层分别包括J,K,M个神经元,它的总输出是个M维矢量,Y= ,第i层到第i+1层之间的权重系数用 来表示。可设前向三层神经网络输出各个分量的理想值是 ,i=0,1,……M-1,而这些分量的实际值是 , i=0,1,……M-1,理想值和实际值之间的误差是 。各输出误差的平方和可以表示为: (6) 现在我们希望改变网络中的各个加权系数 ,使得 尽可能的减小。为此我们可以采取最陡下降算法的公式来调整权重系数 。公式如下: 式中的 是学习的步幅,它应随学习过程而变化。 对于通用神经层,它的各个输出 与各个输入 之间的关系可以表示为: 如果设 ,则 式中的 表示s型函数。我们不难看出上式即为给输入加个恒等于1的部分,在神经网络中也应相应的加个节点,而且这个节点的权系数就是这层网络的阈值。经推倒可得权系数调整的递推公式如下: (7) 对输出层: 对隐含层: 现对于三层神经网络有 l=3时(输出层) l=2时(隐含层) l=1时(第层) 其中: 可见,这算法的计算过程是先计算第三层(即输出层)的各项“误差分量” ,然 后用 计算第二层(隐含层)的“等效误差分量” ,最后再用 计算第层(隐含层)的“等效误差分量”
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值