感知机及算法实现

在这里插入图片描述

1、感知机二类分类的线性分类模型,输入为实例的特征向量,输出为实例的类别,取+1和-1二值,感知机对应于输入空间中将实例划分为正负两类的分离超平面,属于判别模型。
感知机学习旨在求出将训练数据进行线性划分的分离超平面,为此导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。感知机学习算法具有简单、易于实现的优点,分为原始形式和对偶形式,感知机预测是用学习到的感知机模型对新的输入实例进行分类。

2、感知机:假设输入空间(特征空间)是X⊆R,输出空间Y={+1,-1},输入x∈X表示实例的特征向量,对应于输入空间的点;输出y∈Y表示实例的类别。有输入空间到输出空间的如下函数f(x)=sign(w•x+b)称为感知机,其中w和b为感知机模型参数,w∈R叫做权值或权值向量,b∈R叫做偏置,w•x为内积,sign是符号函数
在这里插入图片描述
感知机是一种线性分类模型,属于判别模型,假设空间是定义在特征空间中所有线性分类模型或线性分类器,即函数集合{f|f(x)=w•x+b}。感知机学习是由训练数据集求得上述感知机模型,即求出模型参数w,b;感知机预测是通过学习得到的感知机模型,对新的输入实例给出对应的输出类别。

3、感知机的几何解释:线性方程w•x+b=0对应于特征空间R中的一个超平面S(分离超平面),其中w是超平面的法向量,b是超平面的截距,这个超平面将特征空间划分为两个部分,位于两部分的点被分为正负两类。

4、数据集的线性可分性:给定一个数据集T={(x1,y1),(x2,y2),…,(xn,yn)},其中xi∈X,yi∈Y={+1,-1},如果存在某个超平面S,w•x+b=0能够将数据集的正实例点和负实例点完全正确地划分到超平面两侧,即对所有yi=+1的实例i,有w•xi+b>0;对所有yi=-1的实例i,有w•xi+b<0,则称数据集T为线性可分数据集,否则称数据集T线性不可分。

5、为了找到能将训练集正实例点和负实例点完全正确分开的分离超平面,需要确定感知机模型形参数w、b,这时需要确定学习策略即定义损失(经验)函数并将损失函数极小化。
损失函数的一个自然选择是误分类点的总数,但是这样的损失函数不是参数w,b的连续可导函数,不易优化,另一个选择是误分类点到超平面S的总距离,这是感知机所采用的。损失函数定义为
在这里插入图片描述
其中,M为误分类点的集合。损失函数是非负的,如果没有误分类点,损失函数值为0,而且误分类点数越少,误分类点离超平面越近,损失函数值越小。

6、感知机算法是误分类驱动的,具体所采用的是随机梯度下降法,首先任意选取一个超平面w0,b0,然后用梯度下降法不断地极小化目标函数,极小化的过程中不是一次使M中所有误分类点的梯度下降,而是一次随机选取一个误分类点使其梯度下降。损失函数L(w,b)的梯度由下式给出。
在这里插入图片描述
随机选择一个误分类点(xi,yi),对w,b进行更新:
在这里插入图片描述
式中η(0<η≤1)是步长,在统计学习中又称为学习率,通过迭代可以期待损失函数不断减小直至0。

7、感知机学习算法的原始形式
输入——训练数据集T={(x1,y1),(x2,y2),…,(xn,yn)},其中xi∈X=R,yi∈Y={+1,-1},i=1,2,…,N,学习率η(0<η≤1)
输出——w,b,感知机模型f(x)=sign(w•x+b)。
(1)选取初值w0,b0;
(2)在训练集中选择数据(xi,yi)
(3)如果yi(w•xi+b)≤0
在这里插入图片描述
(4)转至(2),直至训练集中没有误分类点
算法直观解释——当一个实例点被误分类,位于分离超平面的错误一侧时,则调整w,b的值,使分离超平面向该误分类点的一侧移动,以减少该误分类点与超平面间的距离,直至超平面越过该误分类点使其被正确分类。

# 利用Python实现感知机算法的原始形式
import numpy as np
import matplotlib.pyplot as plt

def createData():
    samples = np.array([[3, 3], [4, 3], [1, 1]])
    labels = [-1, -1, 1]
    return samples, labels

class Perception:
    def __init__(self, x, y, a=1):
        self.x = x
        self.y = y
        self.l_rate = a
        self.w = np.zeros((x.shape[1], 1))
        self.b = 0
        self.numSimples = x.shape[0]
        self.numFeatures = x.shape[1]

    def sign(self, w, b, x):
        y = np.dot(x, w) + b  # x .w + b
        return int(y)

    def update(self, label_i, data_i):
        tmp = label_i * self.l_rate * data_i  # w = w + n yx
        tmp = tmp.reshape(self.w.shape)
        self.w = tmp + self.w
        self.b = self.b + label_i * self.l_rate  # b = b + n y

    def train(self):
        isFind = False
        while not isFind:
            count = 0
            for row in range(self.numSimples):
                simY = self.sign(self.w, self.b, self.x[row, :])
                if simY * self.y[row] <= 0:  # 如果是一个误分类实例点
                    print('误分类点为:', self.x[row, :], '此时的w和b为:', self.w, self.b)
                    count += 1
                    self.update(self.y[row], self.x[row])
            if count == 0:
                print('最终训练得到的w和b为:', self.w, self.b)
                isFind = True
        return self.w, self.b

class Picture:
    def __init__(self, data, w, b):
        self.w = w
        self.b = b
        plt.figure(1)
        plt.title("Perception Learning Algorithm", size=14)
        plt.xlabel("x0", size=14)
        plt.ylabel("x1", size=14)
        xData = np.linspace(0, 5, 100)
        yData = self.expression(xData)
        plt.plot(xData, yData, color='r', label='data')

        plt.scatter(data[0][0], data[0][1], s=50)
        plt.scatter(data[1][0], data[1][1], s=50)
        plt.scatter(data[2][0], data[2][1], s=50, marker='x')
        plt.savefig('2d_base.png', dpi=75)

    def expression(self, x):
        y = (-self.b - self.w[0] * x) / self.w[1]
        # 注意在此,把x0,x1当做两个坐标轴,把x1当做自变量,x2为因变量
        return y
        
    def show_pic(self):
        plt.show()

if __name__ == '__main__':
    samples, labels = createData()
    myperceptron = Perception(x=samples, y=labels)
    weights, bias = myperceptron.train()
    Picture = Picture(samples, weights, bias)
    Picture.show_pic()

8、Novikoff定理
在这里插入图片描述
定理表明,误分类次数k由上界,经过有限次搜索可以找到将训练数据完全正确分开的分离超平面,当训练数据集线性可分时,感知机学习算法原始形式迭代是收敛的。为了得到唯一的超平面,需要对分离超平面增加约束条件。

9、感知机学习算法的对偶形式的基本思路
将w和b表示为实例xi和标记yi的线性组合形式,通过求解其系数求得w和b,可先假设w0、b0均为0,对误分类点先通过下式
在这里插入图片描述
逐步修改w,b,修改n次则w,b关于(xi,yi)的增量分别是αiyixi和αiyi,αi=niη,则最后学习到的w,b可以分别表示为,
在这里插入图片描述
其中αi≥0,当η=1时表示第i个实例点由于误分而进行更新的次数,实例点更新次数越多,意味着它距离分离超平面越近,越难正确分类。

10、感知机学习算法的对偶形式
输入——线性可分训练数据集T={(x1,y1),(x2,y2),…,(xn,yn)},其中xi∈X=R,yi∈Y={+1,-1},i=1,2,…,N,学习率η(0<η≤1)
输出——ɑ,b,感知机模型f(x)=sign(∑ɑjyjxj•x+b)。
其中
在这里插入图片描述
(1)ɑ←0,b←0
(2)在训练集中选取数据(xi,yi)
(3)如果yi(∑ɑjyjxj•xi+b)≤0
在这里插入图片描述
(4)转至(2)直到没有误分类数据。
对偶形式中训练数据仅以内积形式出现,可以预先将训练集中实例间的内积计算出来并以矩阵形式存储,该矩阵即Gram矩阵:G=[xi•xj](NxN)。

# 利用Python实现感知机算法的对偶形式
import numpy as np
import matplotlib.pyplot as plt

# 1、 创建数据集
def createdata():
    samples = np.array([[3, 3], [4, 3], [1, 1]])
    labels = np.array([-1, -1, 1])
    return samples, labels

class Perception:
    def __init__(self, x, y, a=1):
        self.x = x
        self.y = y
        self.w = np.zeros((1, x.shape[0]))
        self.b = 0
        self.a = 1  # 学习率
        self.numsamples = self.x.shape[0]
        self.numfeatures = self.x.shape[1]
        self.gMatrix = self.cal_gram(self.x)

    def cal_gram(self, x):
        gMatrix = np.zeros((self.numsamples, self.numsamples))
        for i in range(self.numsamples):
            for j in range(self.numsamples):
                gMatrix[i][j] = np.dot(self.x[i, :], self.x[j, :])
        return gMatrix

    def sign(self, w, b, key):
        y = np.dot(w * self.y, self.gMatrix[:, key]) + b  # αjYjXjXi + b
        return int(y)

    def update(self, i):
        self.w[:, i] = self.w[:, i] + self.a
        self.b = self.b + self.y[i] * self.a

    def cal_w(self):
        w = np.dot(self.w * self.y, self.x)
        return w

    def train(self):
        isFind = False
        while not isFind:
            count = 0
            for i in range(self.numsamples):
                tmpY = self.sign(self.w, self.b, i)
                if tmpY * self.y[i] <= 0:  # 如果是一个误分类实例点
                    print('误分类点为:', self.x[i, :], '此时的w和b为:', self.cal_w(), ',', self.b)
                    count += 1
                    self.update(i)
            if count == 0:
                print('最终训练得到的w和b为:', self.cal_w(), ',', self.b)
                isFind = True
        weights = self.cal_w()
        return weights, self.b

# 画图描绘
class Picture:
    def __init__(self, data, w, b):
        self.b = b
        self.w = w
        plt.figure(1)
        plt.title('Perception Learning Algorithm', size=14)
        plt.xlabel('x0', size=14)
        plt.ylabel('x1', size=14)

        xData = np.linspace(0, 5, 100)
        yData = self.expression(xData)
        plt.plot(xData, yData, color='r', label='data')

        plt.scatter(data[0][0], data[0][1], s=50)
        plt.scatter(data[1][0], data[1][1], s=50)
        plt.scatter(data[2][0], data[2][1], s=50, marker='x')
        plt.savefig('2d_duio.png', dpi=75)

    def expression(self, x):
        y = (-self.b - self.w[:, 0] * x) / self.w[:, 1]
        return y

    def show_pic(self):
        plt.show()

if __name__ == '__main__':
    samples, labels = createdata()
    myperceptron = Perception(x=samples, y=labels)
    weights, bias = myperceptron.train()
    Picture = Picture(samples, weights, bias)
    Picture.show_pic()

拓展知识

  • 损失函数之所以是非负的,因为每一个误分类点都满足[公式]
    因为当我们数据点正确值为+1的时候,你误分类了,那么判断为-1,则算出来[公式]
    当数据点是正确值为-1的时候,你误分类了,那么判断为+1,则算出来
    在这里插入图片描述
  • 异或问题不能用感知机表示的原因:异或问题可以分为根据输出可以分为两类,显示在二维坐标系中如上图所示:其中输出结果为1对应右图中红色的十字架,输出为0对应右图中蓝色的圆圈,我们可以发现对于这种情况无法找到一条直线将两类结果分开,即感知机无法找到一个线性模型对异或问题进行划分,并且所有的线性分类模型都无法处理异或分类问题。
    在这里插入图片描述

来源:统计学习方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值