感知机算法(统计学习方法)之三

感知机学习算法是对以下最优化问题的算法。给定一个训练数据集
T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T = \{(x_1,y_1), (x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)}其中, x i ∈ X = R n , y i ∈ Y = { + 1 , − 1 } , i = 1 , 2 , ⋯   , N x_{i} \in \mathcal{X}=\mathbf{R}^{n}, \quad y_{i} \in \mathcal{Y}=\{+1,-1\}, \quad i=1,2, \cdots, N xiX=Rn,yiY={+1,1},i=1,2,,N,求参数 w w w b b b,使其转化为以下损失函数极小化问题的解:
minL ⁡ ( w , b ) = − ∑ x i ∈ M y i ( w ∗ x i + b ) \operatorname{minL}(w, b)=-\sum_{x_i \in M}y_i(w * x_i+b) minL(w,b)=xiMyi(wxi+b)其中M为误分类点的集合。

感知机学习算法采用随机梯度下降法(不同于批量梯度下降法,每次随机选择一个误分类点使其梯度下降)

损失函数 L ( w , b ) L(w,b) L(w,b)的梯度定义为:
∇ w L ( w , b ) = − ∑ x i ∈ M y i x i ∇ b L ( w , b ) = − ∑ x i ∈ M y i 1 \begin{aligned} \nabla_{w} L(w, b) &=-\sum_{x_{i} \in M} y_{i} x_{i} \\ \nabla_{b} L(w, b) &=-\sum_{x_{i} \in M} y_{i} \end{aligned} \qquad 1 wL(w,b)bL(w,b)=xiMyixi=xiMyi1首先初始化 w 0 w_0 w0 b 0 b_0 b0(可任意选取),然后随机的选择一个误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),对 w , b w,b w,b进行更新:
w ← w + η y i x i b ← b + η y i 2 \begin{aligned}w \leftarrow w+\eta y_{i} x_{i} \\ b \leftarrow b+\eta y_{i} \end{aligned} \qquad 2 ww+ηyixibb+ηyi2其中 η ( 0 ≤ η ≤ 1 ) \eta(0\le \eta \le1) η(0η1)表示步长,即学习率。

*注:“梯度反映的是空间变量变化趋势的最大值和方向”,梯度下降算法时的原理就是利用了梯度的定义,梯度向量从几何意义上讲,就是函数变化增加最快的地方,沿着梯度向量的方向更容易找到函数的最大值,沿着向量相反的方向,梯度减小最快,更容易找到函数最小值。因此选用了梯度的反方向去更新参数 w , b w,b w,b以对损失函数进行迭代,由此可以从 1 1 1式得到 2 2 2式,符号的变化是因为方向相反。

感知机算法原始形式

输入:线性可分的训练数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \ldots,\left(x_{N}, y_{N}\right)\right\} T={(x1,y1),(x2,y2),,(xN,yN)},其中 x i ∈ X = R n , y i ∈ Y = { + 1 , − 1 } , i = 1 , 2 , ⋯   , N x_{i} \in \mathcal{X}=\mathbf{R}^{n}, \quad y_{i} \in \mathcal{Y}=\{+1,-1\}, \quad i=1,2, \cdots, N xiX=Rn,yiY={+1,1},i=1,2,,N;学习率 η ( 0 ≤ η ≤ 1 ) \eta(0\le \eta \le1) η(0η1)
输出: w , b w,b w,b;感知机模型 f ( x ) = s i g n ( w ⋅ x + b ) f(x) = sign(w \cdot x + b) f(x)=sign(wx+b)

  1. 选取初值 w 0 , b 0 w_0,b_0 w0,b0
  2. 在训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)
  3. i f y i ( w ⋅ x i + b ) ≤ 0 if \quad y_i(w\cdot x_i + b) \le 0 ifyi(wxi+b)0,有 w ← w + η y i x i b ← b + η y i \begin{aligned}w \leftarrow w+\eta y_{i} x_{i} \\ b \leftarrow b+\eta y_{i} \end{aligned} ww+ηyixibb+ηyi
  4. 转到步骤2中,直到训练集中没有误分类点。

算法直观解释:当一个实例点被误分类,即位于分离超平面的错误一侧时,则调整 w , b w,b w,b的值,使分离超平面向该误分类点的一侧移动,以减少该误分类点与超平面之间的距离,直到超平面越过该误分类点使其被正确分类。
原始形式代码实现如下(采用鸢尾花数据集):

import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt

# 数据线性可分,二分类数据
# 此处为一元一次线性方程
class Perceptron(object):
    # 类创建对象时自动执行,进行初始化操作
    def __init__(self, data):
        self.w = np.zeros(len(data[0]) - 1, dtype=np.float32)  # 初始化权重
        self.b = 0  # 初始化截距项
        self.l_rate = 0.1  # 学习步长

    # 定义符号函数
    def sign(self, x, w, b):
        y = np.dot(x, w) + b
        return y

    # 随机梯度下降法
    def fit(self, X_train, Y_train):
        sign = True
        while sign:
            sign = False
            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 # 更新步长
                    sign = True

if __name__ == '__main__':
    # 加载鸢尾花数据集
    iris = load_iris()
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    df['label'] = iris.target

    # 列数据标注
    df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']

    # 选取特征和标签
    data = np.array(df.iloc[:100, [0, 1, -1]])
    X, Y = data[:, :-1], data[:, -1]
    Y = np.array([1 if i == 1 else -1 for i in Y])  # 将label中的0标签替换为-1

    perceptron = Perceptron(data)  # 类的实例化,创建一个对象
    perceptron.fit(X, Y)  # 调用类的fit方法

    # 可视化超平面
    x = np.linspace(4, 7, 10)  # linspace返回固定间隔的数据
    y = -(perceptron.w[0] * x + perceptron.b) / perceptron.w[1]  # 误差分类点到超平面的距离
    plt.plot(x, y)

    # 可视化展示
    plt.plot(data[:50, 0], data[:50, 1], 'x', color='red', label='0')
    plt.plot(data[50:100, 0], data[50:100, 1], 'o', color='black', label='1')
    plt.xlabel('sepal length')
    plt.ylabel('sepal width')
    plt.legend()

输出如下:
在这里插入图片描述
原始形式代码实现2(采用李航统计学习课本案例):

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

class Perceptron(object):
    def __init__(self, data):
        self.w = np.zeros(len(data[0]) - 1, dtype=np.float32)  # 初始化权重数组
        self.b = 0  # 初始化截距项
        self.l_rate = 0.1  # 学习步长

    # 定义符号函数
    def sign(self, x, w, b):
        y = np.dot(x, w) + b
        return y

    # 随机梯度下降法
    def fit(self, X_train, Y_train):
        sign = True
        while sign:
            sign = False
            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 # 更新步长
                    sign = True

if __name__ == '__main__':
    data = np.array([[3,3,1],[4,3,1],[1,1,-1]])
    X, Y = data[:, :-1], data[:, -1]
    perceptron = Perceptron(data)
    perceptron.fit(X, Y)

    # 可视化超平面
    x = np.linspace(1, 4, 5)  # linspace返回固定间隔的数据
    y = -(perceptron.w[0] * x + perceptron.b) / perceptron.w[1]  # 误差分类点到超平面的距离
    plt.plot(x, y)

    # 可视化展示
    plt.plot(data[:2, 0], data[:2, 1], '+', color='red', label='good')
    plt.plot(data[2:100, 0], data[2:, 1], 'o', color='black', label='bad')
    plt.xlabel('x^(1)')
    plt.ylabel('x^(2)')
    plt.legend()

实现效果如下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值