(笔记+代码+习题)统计学习方法第二章 感知机

一、机器学习的老祖宗——感知机

感知机1957年由Rosenblatt提出,是神经网络与支持向量机的基础。是二类分类的线性分类模型,属于判别模型,旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。

  • 训练数据集:线性可分(必存在超平面将训练集正负实例分开)
  • 学习目标:找到一个将训练集正、负实例点完全正确分开的超平面
  • 具体学习对象 w 、 b w、b wb
  • **学习策略:**误分类点到超平面S的总距离最小
  • **算法形式:**原始形式+对偶形式

二、从机器学习的三要素角度来详细认识感知机

1、模型

  • 输入空间(特征空间)是 χ ⊆ R n \chi \subseteq R^{n} χRn,输入 x ∈ χ x\in \chi xχ 表示实例的特征向量

  • 输出空间是 Y = { + 1 , − 1 } Y=\{+1,-1\} Y={ +1,1},输出 y ∈ Y y \in Y yY表示实例的类别。

  • 输入空间 —> 输出空间:

    f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot x+b) f(x)=sign(wx+b)

其中, ∗ ∗ w **w w b b b为感知机模型参数,也就是我们机器学习最终要学习的参数**。

sign是符号函数,

s i g n ( x ) = { + 1 , x > 0 − 1 , x < 0 sign(x)=\left\{\begin{matrix}+1,x>0\\ -1,x<0\end{matrix}\right. sign(x)={ +1,x>01,x<0

2、策略

确定学习策略就是定义**(经验)损失函数并将损失函数最小化。(注意这里提到了经验**,所以学习是base在训练数据集上的操作)

关于损失函数的选择问题?

我们对损失函数的要求就是参数 w , b w,b wb的连续可导函数,这样才易优化(后面随机梯度来优化,不可导何谈梯度)。为此,感知机的损失函数选择了:误分类点到超平面 S S S的总距离,而不是误分类点的总数。

数学形式:

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b)=-\sum_{x_i\in M}y_i(w\cdot x_i+b) L(w,b)=xiMyi(wxi+b)

其中 M M M是误分类点的集合,给定训练数据集 T T T,损失函数 L ( w , b ) L(w,b) L(w,b) w w w b b b的连续可导函数

3、算法——原始形式

  • 输入

    T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) x i ∈ χ = R n , y i ∈ Y = − 1 , + 1 , i = 1 , 2 , . . . , N ; 0 < η ⩽ 1 T={(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)}\\x_{i} \in \chi = R^{n} ,y_{i} \in Y={-1,+1},i=1,2,...,N;0<\eta\leqslant 1 T=(x1,y1),(x2,y2),,(xN,yN)xiχ=Rn,yiY=1,+1,i=1,2,...N0<η1

  • 输出

    w , b ; f ( x ) = s i g n ( w ⋅ x + b ) w,b;f(x)=sign(w\cdot x+b) w,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. 如果 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0

      w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

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

  • 步骤解释:

    • 步骤1:

      初始超平面一般选 w 0 = 0 , b 0 = 0 w_0=0,b_0=0 w0=0,b0=0,不同的初始值会学习出不同满足条件的模型,多解问题。

    • 步骤2:

      每次选一个数据点判断是不是误判,不是的话不修正参数,直接下一轮。

    • 步骤3:

      • 极小化过程中不是一次使所有误分类点的梯度下降,而是每次随机选取一个误分类点使其梯度下降(随机梯度法),如3中的 ( x i , y i ) (x_i,y_i) (xi,yi)这一误分类点
      • 如果 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,说明 y i 、 f ( x i ) y_i、f(x_i) yif(xi)异号,则如3中满足 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0
      • 梯度可以由上面损失函数的数学形式看出
    • 步骤4:

      步骤4可能是算法中最不好理解的地方,我学到这里的疑问是:

      用上面的步骤为什么能实现”直至训练集中没有误分类点“?

      这里其实涉及到一个普遍且重要的问题——算法的收敛性,换句话说,我们的算法有效的话,那么经过有限次修正之后一定能找到符合终止条件的模型。

      证明请见:Novikoff定理证明

4、算法——对偶形式

对偶形式的基本思想是将 w w w b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数而求得 w w w b b b

原始形式中对误分类点 ( x i , y i ) (x_i,y_i) (xi,yi)通过:

w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

来修正。假设对于某误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),一共修正了 n i n_i ni次,那么:

w ← w + n i η y i x i b ← b + n i η y i w\leftarrow w+n_i\eta y_ix_i \\ b\leftarrow b+n_i\eta y_i ww+niηyixibb+niηyi

那么,对于所有数据点 w , b w,b w,b的变化就是:

w ← w + ∑ i = 1 N n i η y i x i b ← b + ∑ i = 1 N n i η y i w\leftarrow w+\sum_{i=1}^{N} n_i\eta y_ix_i \\ b\leftarrow b+\sum_{i=1}^{N}n_i\eta y_i ww+i=1Nniηyixibb+i=1Nniηyi

如果令初始 w 0 = 0 , b 0 = 0 , α i = n i η w_0=0,b_0=0,\alpha_i = n_i\eta w0=0,b0=0,αi=niη,则有:

w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w=\sum_{i=1}^{N} \alpha_i y_ix_i \\ b=\sum_{i=1}^{N}\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

在原始形式中,我们是要学习 w , b w,b w,b,现在可以转化为 α 、 b \alpha 、b αb

对偶形式:

  • 输入:

    T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } x i ∈ X = R n , y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N ; 0 < η ⩽ 1 T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\}\\ x_i\in {X}=\bf{R}^n , y_i\in {Y} =\{-1,+1\}, i=1,2,\dots, N; 0< \eta \leqslant 1 T={ (x1,y1),(x2,y2),,(xN,yN)}xiX=Rn,yiY={ 1,+1},i=1,2,,N;0<η1

  • 输出:

    α , b ; f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) α = ( α 1 , α 2 , . . . α N ) T \alpha ,b; f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b)\\\alpha=(\alpha_1,\alpha_2,...\alpha_N)^T α,b;f(x)=sign(j=1Nαjyjxjx+b)α=(α1,α2,...αN)T

  • 步骤:

    1. α ← 0 , b ← 0 \alpha \leftarrow 0,b\leftarrow 0 α0,b0

    2. 训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)

    3. 如果 y i ( ∑ j = 1 N α j y j x j ⋅ x + b ) ⩽ 0 y_i\left(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b\right) \leqslant 0 yi(j=1Nαjyjxjx+b)0

      α i ← α i + η b ← b + η y i \alpha_i\leftarrow \alpha_i+\eta \\b\leftarrow b+\eta y_i αiαi+ηbb+ηyi

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

  • 步骤解释:

    • 步骤1:和前面一样,初始值取0

    • 步骤2:每次也是选取一个数据

    • 步骤3:

      • 如果数据点是误判点的话,开始修正
      • 这里关注一下梯度的计算:对于每一个数据 ( x i , y i ) (x_i,y_i) (xi,yi)每一次修正来说, α i \alpha_i αi的变化量是: η \eta η b b b还是 η y i \eta y_i ηyi不变
    • 步骤4:与原始形式一样,感知机学习算法的对偶形式迭代是收敛的,存在多个解

Gram matrix

对偶形式中,训练实例仅以内积的形式出现。

为了方便可预先将训练集中的实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram矩阵

G = [ x i ⋅ x j ] N × N G=[x_i\cdot x_j]_{N\times N} G=[xixj]N×N

三、代码实现

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

#加载数据
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'
]
print(df.label.value_counts())

#画出原始数据离散图
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('original data')
plt.legend()
plt.show()

data = np.array(df.iloc[:100, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
print("X: ",X)
print("y: ",y)
y = np.array([1 if i == 1 else -1 for i in y])

#感知机模型
# 数据线性可分,二分类数据
# 此处为一元一次线性方程
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)

#画出训练结果
x_points = np.linspace(4, 7, 10)
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('result')
plt.legend()
plt.show()

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hS62NC6Z-1636977901727)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d3b23003-63be-495a-bbb9-ba3b3a16a9ec/Untitled.png)]

习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual## 一、机器学习的老祖宗——感知机

感知机1957年由Rosenblatt提出,是神经网络与支持向量机的基础。是二类分类的线性分类模型,属于判别模型,旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。

  • 训练数据集:线性可分(必存在超平面将训练集正负实例分开)
  • 学习目标:找到一个将训练集正、负实例点完全正确分开的超平面
  • 具体学习对象 w 、 b w、b wb
  • **学习策略:**误分类点到超平面S的总距离最小
  • **算法形式:**原始形式+对偶形式

二、从机器学习的三要素角度来详细认识感知机

1、模型

  • 输入空间(特征空间)是 χ ⊆ R n \chi \subseteq R^{n} χRn,输入 x ∈ χ x\in \chi xχ 表示实例的特征向量

  • 输出空间是 Y = { + 1 , − 1 } Y=\{+1,-1\} Y={ +1,1},输出 y ∈ Y y \in Y yY表示实例的类别。

  • 输入空间 —> 输出空间:

    f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot x+b) f(x)=sign(wx+b)

其中, ∗ ∗ w **w w b b b为感知机模型参数,也就是我们机器学习最终要学习的参数**。

sign是符号函数,

s i g n ( x ) = { + 1 , x > 0 − 1 , x < 0 sign(x)=\left\{\begin{matrix}+1,x>0\\ -1,x<0\end{matrix}\right. sign(x)={ +1,x>01,x<0

2、策略

确定学习策略就是定义**(经验)损失函数并将损失函数最小化。(注意这里提到了经验**,所以学习是base在训练数据集上的操作)

关于损失函数的选择问题?

我们对损失函数的要求就是参数 w , b w,b wb的连续可导函数,这样才易优化(后面随机梯度来优化,不可导何谈梯度)。为此,感知机的损失函数选择了:误分类点到超平面 S S S的总距离,而不是误分类点的总数。

数学形式:

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b)=-\sum_{x_i\in M}y_i(w\cdot x_i+b) L(w,b)=xiMyi(wxi+b)

其中 M M M是误分类点的集合,给定训练数据集 T T T,损失函数 L ( w , b ) L(w,b) L(w,b) w w w b b b的连续可导函数

3、算法——原始形式

  • 输入

    T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) x i ∈ χ = R n , y i ∈ Y = − 1 , + 1 , i = 1 , 2 , . . . , N ; 0 < η ⩽ 1 T={(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)}\\x_{i} \in \chi = R^{n} ,y_{i} \in Y={-1,+1},i=1,2,...,N;0<\eta\leqslant 1 T=(x1,y1),(x2,y2),,(xN,yN)xiχ=Rn,yiY=1,+1,i=1,2,...N0<η1

  • 输出

    w , b ; f ( x ) = s i g n ( w ⋅ x + b ) w,b;f(x)=sign(w\cdot x+b) w,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. 如果 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0

      w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

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

  • 步骤解释:

    • 步骤1:

      初始超平面一般选 w 0 = 0 , b 0 = 0 w_0=0,b_0=0 w0=0,b0=0,不同的初始值会学习出不同满足条件的模型,多解问题。

    • 步骤2:

      每次选一个数据点判断是不是误判,不是的话不修正参数,直接下一轮。

    • 步骤3:

      • 极小化过程中不是一次使所有误分类点的梯度下降,而是每次随机选取一个误分类点使其梯度下降(随机梯度法),如3中的 ( x i , y i ) (x_i,y_i) (xi,yi)这一误分类点
      • 如果 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,说明 y i 、 f ( x i ) y_i、f(x_i) yif(xi)异号,则如3中满足 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0
      • 梯度可以由上面损失函数的数学形式看出
    • 步骤4:

      步骤4可能是算法中最不好理解的地方,我学到这里的疑问是:

      用上面的步骤为什么能实现”直至训练集中没有误分类点“?

      这里其实涉及到一个普遍且重要的问题——算法的收敛性,换句话说,我们的算法有效的话,那么经过有限次修正之后一定能找到符合终止条件的模型。

      证明请见:Novikoff定理证明

4、算法——对偶形式

对偶形式的基本思想是将 w w w b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数而求得 w w w b b b

原始形式中对误分类点 ( x i , y i ) (x_i,y_i) (xi,yi)通过:

w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

来修正。假设对于某误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),一共修正了 n i n_i ni次,那么:

w ← w + n i η y i x i b ← b + n i η y i w\leftarrow w+n_i\eta y_ix_i \\ b\leftarrow b+n_i\eta y_i ww+niηyixibb+niηyi

那么,对于所有数据点 w , b w,b w,b的变化就是:

w ← w + ∑ i = 1 N n i η y i x i b ← b + ∑ i = 1 N n i η y i w\leftarrow w+\sum_{i=1}^{N} n_i\eta y_ix_i \\ b\leftarrow b+\sum_{i=1}^{N}n_i\eta y_i ww+i=1Nniηyixibb+i=1Nniηyi

如果令初始 w 0 = 0 , b 0 = 0 , α i = n i η w_0=0,b_0=0,\alpha_i = n_i\eta w0=0,b0=0,αi=niη,则有:

w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w=\sum_{i=1}^{N} \alpha_i y_ix_i \\ b=\sum_{i=1}^{N}\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

在原始形式中,我们是要学习 w , b w,b w,b,现在可以转化为 α 、 b \alpha 、b αb

对偶形式:

  • 输入:

    T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } x i ∈ X = R n , y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N ; 0 < η ⩽ 1 T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\}\\ x_i\in {X}=\bf{R}^n , y_i\in {Y} =\{-1,+1\}, i=1,2,\dots, N; 0< \eta \leqslant 1 T={ (x1,y1),(x2,y2),,(xN,yN)}xiX=Rn,yiY={ 1,+1},i=1,2,,N;0<η1

  • 输出:

    α , b ; f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) α = ( α 1 , α 2 , . . . α N ) T \alpha ,b; f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b)\\\alpha=(\alpha_1,\alpha_2,...\alpha_N)^T α,b;f(x)=sign(j=1Nαjyjxjx+b)α=(α1,α2,...αN)T

  • 步骤:

    1. α ← 0 , b ← 0 \alpha \leftarrow 0,b\leftarrow 0 α0,b0

    2. 训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)

    3. 如果 y i ( ∑ j = 1 N α j y j x j ⋅ x + b ) ⩽ 0 y_i\left(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b\right) \leqslant 0 yi(j=1Nαjyjxjx+b)0

      α i ← α i + η b ← b + η y i \alpha_i\leftarrow \alpha_i+\eta \\b\leftarrow b+\eta y_i αiαi+ηbb+ηyi

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

  • 步骤解释:

    • 步骤1:和前面一样,初始值取0

    • 步骤2:每次也是选取一个数据

    • 步骤3:

      • 如果数据点是误判点的话,开始修正
      • 这里关注一下梯度的计算:对于每一个数据 ( x i , y i ) (x_i,y_i) (xi,yi)每一次修正来说, α i \alpha_i αi的变化量是: η \eta η b b b还是 η y i \eta y_i ηyi不变
    • 步骤4:与原始形式一样,感知机学习算法的对偶形式迭代是收敛的,存在多个解

Gram matrix

对偶形式中,训练实例仅以内积的形式出现。

为了方便可预先将训练集中的实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram矩阵

G = [ x i ⋅ x j ] N × N G=[x_i\cdot x_j]_{N\times N} G=[xixj]N×N

三、代码实现

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

#加载数据
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'
]
print(df.label.value_counts())

#画出原始数据离散图
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('original data')
plt.legend()
plt.show()

data = np.array(df.iloc[:100, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
print("X: ",X)
print("y: ",y)
y = np.array([1 if i == 1 else -1 for i in y])

#感知机模型
# 数据线性可分,二分类数据
# 此处为一元一次线性方程
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)

#画出训练结果
x_points = np.linspace(4, 7, 10)
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('result')
plt.legend()
plt.show()

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01X1BWFf-1636977902626)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d3b23003-63be-495a-bbb9-ba3b3a16a9ec/Untitled.png)]

习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual## 一、机器学习的老祖宗——感知机

感知机1957年由Rosenblatt提出,是神经网络与支持向量机的基础。是二类分类的线性分类模型,属于判别模型,旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。

  • 训练数据集:线性可分(必存在超平面将训练集正负实例分开)
  • 学习目标:找到一个将训练集正、负实例点完全正确分开的超平面
  • 具体学习对象 w 、 b w、b wb
  • **学习策略:**误分类点到超平面S的总距离最小
  • **算法形式:**原始形式+对偶形式

二、从机器学习的三要素角度来详细认识感知机

1、模型

  • 输入空间(特征空间)是 χ ⊆ R n \chi \subseteq R^{n} χRn,输入 x ∈ χ x\in \chi xχ 表示实例的特征向量

  • 输出空间是 Y = { + 1 , − 1 } Y=\{+1,-1\} Y={ +1,1},输出 y ∈ Y y \in Y yY表示实例的类别。

  • 输入空间 —> 输出空间:

    f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot x+b) f(x)=sign(wx+b)

其中, ∗ ∗ w **w w b b b为感知机模型参数,也就是我们机器学习最终要学习的参数**。

sign是符号函数,

s i g n ( x ) = { + 1 , x > 0 − 1 , x < 0 sign(x)=\left\{\begin{matrix}+1,x>0\\ -1,x<0\end{matrix}\right. sign(x)={ +1,x>01,x<0

2、策略

确定学习策略就是定义**(经验)损失函数并将损失函数最小化。(注意这里提到了经验**,所以学习是base在训练数据集上的操作)

关于损失函数的选择问题?

我们对损失函数的要求就是参数 w , b w,b wb的连续可导函数,这样才易优化(后面随机梯度来优化,不可导何谈梯度)。为此,感知机的损失函数选择了:误分类点到超平面 S S S的总距离,而不是误分类点的总数。

数学形式:

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b)=-\sum_{x_i\in M}y_i(w\cdot x_i+b) L(w,b)=xiMyi(wxi+b)

其中 M M M是误分类点的集合,给定训练数据集 T T T,损失函数 L ( w , b ) L(w,b) L(w,b) w w w b b b的连续可导函数

3、算法——原始形式

  • 输入

    T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) x i ∈ χ = R n , y i ∈ Y = − 1 , + 1 , i = 1 , 2 , . . . , N ; 0 < η ⩽ 1 T={(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)}\\x_{i} \in \chi = R^{n} ,y_{i} \in Y={-1,+1},i=1,2,...,N;0<\eta\leqslant 1 T=(x1,y1),(x2,y2),,(xN,yN)xiχ=Rn,yiY=1,+1,i=1,2,...N0<η1

  • 输出

    w , b ; f ( x ) = s i g n ( w ⋅ x + b ) w,b;f(x)=sign(w\cdot x+b) w,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. 如果 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0

      w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

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

  • 步骤解释:

    • 步骤1:

      初始超平面一般选 w 0 = 0 , b 0 = 0 w_0=0,b_0=0 w0=0,b0=0,不同的初始值会学习出不同满足条件的模型,多解问题。

    • 步骤2:

      每次选一个数据点判断是不是误判,不是的话不修正参数,直接下一轮。

    • 步骤3:

      • 极小化过程中不是一次使所有误分类点的梯度下降,而是每次随机选取一个误分类点使其梯度下降(随机梯度法),如3中的 ( x i , y i ) (x_i,y_i) (xi,yi)这一误分类点
      • 如果 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,说明 y i 、 f ( x i ) y_i、f(x_i) yif(xi)异号,则如3中满足 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0
      • 梯度可以由上面损失函数的数学形式看出
    • 步骤4:

      步骤4可能是算法中最不好理解的地方,我学到这里的疑问是:

      用上面的步骤为什么能实现”直至训练集中没有误分类点“?

      这里其实涉及到一个普遍且重要的问题——算法的收敛性,换句话说,我们的算法有效的话,那么经过有限次修正之后一定能找到符合终止条件的模型。

      证明请见:Novikoff定理证明

4、算法——对偶形式

对偶形式的基本思想是将 w w w b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数而求得 w w w b b b

原始形式中对误分类点 ( x i , y i ) (x_i,y_i) (xi,yi)通过:

w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

来修正。假设对于某误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),一共修正了 n i n_i ni次,那么:

w ← w + n i η y i x i b ← b + n i η y i w\leftarrow w+n_i\eta y_ix_i \\ b\leftarrow b+n_i\eta y_i ww+niηyixibb+niηyi

那么,对于所有数据点 w , b w,b w,b的变化就是:

w ← w + ∑ i = 1 N n i η y i x i b ← b + ∑ i = 1 N n i η y i w\leftarrow w+\sum_{i=1}^{N} n_i\eta y_ix_i \\ b\leftarrow b+\sum_{i=1}^{N}n_i\eta y_i ww+i=1Nniηyixibb+i=1Nniηyi

如果令初始 w 0 = 0 , b 0 = 0 , α i = n i η w_0=0,b_0=0,\alpha_i = n_i\eta w0=0,b0=0,αi=niη,则有:

w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w=\sum_{i=1}^{N} \alpha_i y_ix_i \\ b=\sum_{i=1}^{N}\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

在原始形式中,我们是要学习 w , b w,b w,b,现在可以转化为 α 、 b \alpha 、b αb

对偶形式:

  • 输入:

    T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } x i ∈ X = R n , y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N ; 0 < η ⩽ 1 T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\}\\ x_i\in {X}=\bf{R}^n , y_i\in {Y} =\{-1,+1\}, i=1,2,\dots, N; 0< \eta \leqslant 1 T={ (x1,y1),(x2,y2),,(xN,yN)}xiX=Rn,yiY={ 1,+1},i=1,2,,N;0<η1

  • 输出:

    α , b ; f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) α = ( α 1 , α 2 , . . . α N ) T \alpha ,b; f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b)\\\alpha=(\alpha_1,\alpha_2,...\alpha_N)^T α,b;f(x)=sign(j=1Nαjyjxjx+b)α=(α1,α2,...αN)T

  • 步骤:

    1. α ← 0 , b ← 0 \alpha \leftarrow 0,b\leftarrow 0 α0,b0

    2. 训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)

    3. 如果 y i ( ∑ j = 1 N α j y j x j ⋅ x + b ) ⩽ 0 y_i\left(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b\right) \leqslant 0 yi(j=1Nαjyjxjx+b)0

      α i ← α i + η b ← b + η y i \alpha_i\leftarrow \alpha_i+\eta \\b\leftarrow b+\eta y_i αiαi+ηbb+ηyi

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

  • 步骤解释:

    • 步骤1:和前面一样,初始值取0

    • 步骤2:每次也是选取一个数据

    • 步骤3:

      • 如果数据点是误判点的话,开始修正
      • 这里关注一下梯度的计算:对于每一个数据 ( x i , y i ) (x_i,y_i) (xi,yi)每一次修正来说, α i \alpha_i αi的变化量是: η \eta η b b b还是 η y i \eta y_i ηyi不变
    • 步骤4:与原始形式一样,感知机学习算法的对偶形式迭代是收敛的,存在多个解

Gram matrix

对偶形式中,训练实例仅以内积的形式出现。

为了方便可预先将训练集中的实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram矩阵

G = [ x i ⋅ x j ] N × N G=[x_i\cdot x_j]_{N\times N} G=[xixj]N×N

三、代码实现

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

#加载数据
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'
]
print(df.label.value_counts())

#画出原始数据离散图
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('original data')
plt.legend()
plt.show()

data = np.array(df.iloc[:100, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
print("X: ",X)
print("y: ",y)
y = np.array([1 if i == 1 else -1 for i in y])

#感知机模型
# 数据线性可分,二分类数据
# 此处为一元一次线性方程
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)

#画出训练结果
x_points = np.linspace(4, 7, 10)
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('result')
plt.legend()
plt.show()

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MCZCHEP6-1636977902840)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d3b23003-63be-495a-bbb9-ba3b3a16a9ec/Untitled.png)]

习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual## 一、机器学习的老祖宗——感知机

感知机1957年由Rosenblatt提出,是神经网络与支持向量机的基础。是二类分类的线性分类模型,属于判别模型,旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。

  • 训练数据集:线性可分(必存在超平面将训练集正负实例分开)
  • 学习目标:找到一个将训练集正、负实例点完全正确分开的超平面
  • 具体学习对象 w 、 b w、b wb
  • **学习策略:**误分类点到超平面S的总距离最小
  • **算法形式:**原始形式+对偶形式

二、从机器学习的三要素角度来详细认识感知机

1、模型

  • 输入空间(特征空间)是 χ ⊆ R n \chi \subseteq R^{n} χRn,输入 x ∈ χ x\in \chi xχ 表示实例的特征向量

  • 输出空间是 Y = { + 1 , − 1 } Y=\{+1,-1\} Y={ +1,1},输出 y ∈ Y y \in Y yY表示实例的类别。

  • 输入空间 —> 输出空间:

    f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot x+b) f(x)=sign(wx+b)

其中, ∗ ∗ w **w w b b b为感知机模型参数,也就是我们机器学习最终要学习的参数**。

sign是符号函数,

s i g n ( x ) = { + 1 , x > 0 − 1 , x < 0 sign(x)=\left\{\begin{matrix}+1,x>0\\ -1,x<0\end{matrix}\right. sign(x)={ +1,x>01,x<0

2、策略

确定学习策略就是定义**(经验)损失函数并将损失函数最小化。(注意这里提到了经验**,所以学习是base在训练数据集上的操作)

关于损失函数的选择问题?

我们对损失函数的要求就是参数 w , b w,b wb的连续可导函数,这样才易优化(后面随机梯度来优化,不可导何谈梯度)。为此,感知机的损失函数选择了:误分类点到超平面 S S S的总距离,而不是误分类点的总数。

数学形式:

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b)=-\sum_{x_i\in M}y_i(w\cdot x_i+b) L(w,b)=xiMyi(wxi+b)

其中 M M M是误分类点的集合,给定训练数据集 T T T,损失函数 L ( w , b ) L(w,b) L(w,b) w w w b b b的连续可导函数

3、算法——原始形式

  • 输入

    T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) x i ∈ χ = R n , y i ∈ Y = − 1 , + 1 , i = 1 , 2 , . . . , N ; 0 < η ⩽ 1 T={(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)}\\x_{i} \in \chi = R^{n} ,y_{i} \in Y={-1,+1},i=1,2,...,N;0<\eta\leqslant 1 T=(x1,y1),(x2,y2),,(xN,yN)xiχ=Rn,yiY=1,+1,i=1,2,...N0<η1

  • 输出

    w , b ; f ( x ) = s i g n ( w ⋅ x + b ) w,b;f(x)=sign(w\cdot x+b) w,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. 如果 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0

      w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

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

  • 步骤解释:

    • 步骤1:

      初始超平面一般选 w 0 = 0 , b 0 = 0 w_0=0,b_0=0 w0=0,b0=0,不同的初始值会学习出不同满足条件的模型,多解问题。

    • 步骤2:

      每次选一个数据点判断是不是误判,不是的话不修正参数,直接下一轮。

    • 步骤3:

      • 极小化过程中不是一次使所有误分类点的梯度下降,而是每次随机选取一个误分类点使其梯度下降(随机梯度法),如3中的 ( x i , y i ) (x_i,y_i) (xi,yi)这一误分类点
      • 如果 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,说明 y i 、 f ( x i ) y_i、f(x_i) yif(xi)异号,则如3中满足 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0
      • 梯度可以由上面损失函数的数学形式看出
    • 步骤4:

      步骤4可能是算法中最不好理解的地方,我学到这里的疑问是:

      用上面的步骤为什么能实现”直至训练集中没有误分类点“?

      这里其实涉及到一个普遍且重要的问题——算法的收敛性,换句话说,我们的算法有效的话,那么经过有限次修正之后一定能找到符合终止条件的模型。

      证明请见:Novikoff定理证明

4、算法——对偶形式

对偶形式的基本思想是将 w w w b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数而求得 w w w b b b

原始形式中对误分类点 ( x i , y i ) (x_i,y_i) (xi,yi)通过:

w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

来修正。假设对于某误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),一共修正了 n i n_i ni次,那么:

w ← w + n i η y i x i b ← b + n i η y i w\leftarrow w+n_i\eta y_ix_i \\ b\leftarrow b+n_i\eta y_i ww+niηyixibb+niηyi

那么,对于所有数据点 w , b w,b w,b的变化就是:

w ← w + ∑ i = 1 N n i η y i x i b ← b + ∑ i = 1 N n i η y i w\leftarrow w+\sum_{i=1}^{N} n_i\eta y_ix_i \\ b\leftarrow b+\sum_{i=1}^{N}n_i\eta y_i ww+i=1Nniηyixibb+i=1Nniηyi

如果令初始 w 0 = 0 , b 0 = 0 , α i = n i η w_0=0,b_0=0,\alpha_i = n_i\eta w0=0,b0=0,αi=niη,则有:

w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w=\sum_{i=1}^{N} \alpha_i y_ix_i \\ b=\sum_{i=1}^{N}\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

在原始形式中,我们是要学习 w , b w,b w,b,现在可以转化为 α 、 b \alpha 、b αb

对偶形式:

  • 输入:

    T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } x i ∈ X = R n , y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N ; 0 < η ⩽ 1 T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\}\\ x_i\in {X}=\bf{R}^n , y_i\in {Y} =\{-1,+1\}, i=1,2,\dots, N; 0< \eta \leqslant 1 T={ (x1,y1),(x2,y2),,(xN,yN)}xiX=Rn,yiY={ 1,+1},i=1,2,,N;0<η1

  • 输出:

    α , b ; f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) α = ( α 1 , α 2 , . . . α N ) T \alpha ,b; f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b)\\\alpha=(\alpha_1,\alpha_2,...\alpha_N)^T α,b;f(x)=sign(j=1Nαjyjxjx+b)α=(α1,α2,...αN)T

  • 步骤:

    1. α ← 0 , b ← 0 \alpha \leftarrow 0,b\leftarrow 0 α0,b0

    2. 训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)

    3. 如果 y i ( ∑ j = 1 N α j y j x j ⋅ x + b ) ⩽ 0 y_i\left(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b\right) \leqslant 0 yi(j=1Nαjyjxjx+b)0

      α i ← α i + η b ← b + η y i \alpha_i\leftarrow \alpha_i+\eta \\b\leftarrow b+\eta y_i αiαi+ηbb+ηyi

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

  • 步骤解释:

    • 步骤1:和前面一样,初始值取0

    • 步骤2:每次也是选取一个数据

    • 步骤3:

      • 如果数据点是误判点的话,开始修正
      • 这里关注一下梯度的计算:对于每一个数据 ( x i , y i ) (x_i,y_i) (xi,yi)每一次修正来说, α i \alpha_i αi的变化量是: η \eta η b b b还是 η y i \eta y_i ηyi不变
    • 步骤4:与原始形式一样,感知机学习算法的对偶形式迭代是收敛的,存在多个解

Gram matrix

对偶形式中,训练实例仅以内积的形式出现。

为了方便可预先将训练集中的实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram矩阵

G = [ x i ⋅ x j ] N × N G=[x_i\cdot x_j]_{N\times N} G=[xixj]N×N

三、代码实现

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

#加载数据
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'
]
print(df.label.value_counts())

#画出原始数据离散图
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('original data')
plt.legend()
plt.show()

data = np.array(df.iloc[:100, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
print("X: ",X)
print("y: ",y)
y = np.array([1 if i == 1 else -1 for i in y])

#感知机模型
# 数据线性可分,二分类数据
# 此处为一元一次线性方程
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)

#画出训练结果
x_points = np.linspace(4, 7, 10)
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('result')
plt.legend()
plt.show()

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AxFc4sse-1636977903094)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d3b23003-63be-495a-bbb9-ba3b3a16a9ec/Untitled.png)]

习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual## 一、机器学习的老祖宗——感知机

感知机1957年由Rosenblatt提出,是神经网络与支持向量机的基础。是二类分类的线性分类模型,属于判别模型,旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。

  • 训练数据集:线性可分(必存在超平面将训练集正负实例分开)
  • 学习目标:找到一个将训练集正、负实例点完全正确分开的超平面
  • 具体学习对象 w 、 b w、b wb
  • **学习策略:**误分类点到超平面S的总距离最小
  • **算法形式:**原始形式+对偶形式

二、从机器学习的三要素角度来详细认识感知机

1、模型

  • 输入空间(特征空间)是 χ ⊆ R n \chi \subseteq R^{n} χRn,输入 x ∈ χ x\in \chi xχ 表示实例的特征向量

  • 输出空间是 Y = { + 1 , − 1 } Y=\{+1,-1\} Y={ +1,1},输出 y ∈ Y y \in Y yY表示实例的类别。

  • 输入空间 —> 输出空间:

    f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot x+b) f(x)=sign(wx+b)

其中, ∗ ∗ w **w w b b b为感知机模型参数,也就是我们机器学习最终要学习的参数**。

sign是符号函数,

s i g n ( x ) = { + 1 , x > 0   − 1 , x < 0 sign(x)=\left\{\begin{matrix}+1,x>0\\ -1,x<0\end{matrix}\right. sign(x)={ +1,x>0 1,x<0

2、策略

确定学习策略就是定义**(经验)损失函数并将损失函数最小化。(注意这里提到了经验**,所以学习是base在训练数据集上的操作)

关于损失函数的选择问题?

我们对损失函数的要求就是参数 w , b w,b wb的连续可导函数,这样才易优化(后面随机梯度来优化,不可导何谈梯度)。为此,感知机的损失函数选择了:误分类点到超平面 S S S的总距离,而不是误分类点的总数。

数学形式:

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b)=-\sum_{x_i\in M}y_i(w\cdot x_i+b) L(w,b)=xiMyi(wxi+b)

其中 M M M是误分类点的集合,给定训练数据集 T T T,损失函数 L ( w , b ) L(w,b) L(w,b) w w w b b b的连续可导函数

3、算法——原始形式

  • 输入

    T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) x i ∈ χ = R n , y i ∈ Y = − 1 , + 1 , i = 1 , 2 , . . . , N ; 0 < η ⩽ 1 T={(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)}\\x_{i} \in \chi = R^{n} ,y_{i} \in Y={-1,+1},i=1,2,...,N;0<\eta\leqslant 1 T=(x1,y1),(x2,y2),,(xN,yN)xiχ=Rn,yiY=1,+1,i=1,2,...N0<η1

  • 输出

    w , b ; f ( x ) = s i g n ( w ⋅ x + b ) w,b;f(x)=sign(w\cdot x+b) w,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. 如果 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0

      w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

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

  • 步骤解释:

    • 步骤1:

      初始超平面一般选 w 0 = 0 , b 0 = 0 w_0=0,b_0=0 w0=0,b0=0,不同的初始值会学习出不同满足条件的模型,多解问题。

    • 步骤2:

      每次选一个数据点判断是不是误判,不是的话不修正参数,直接下一轮。

    • 步骤3:

      • 极小化过程中不是一次使所有误分类点的梯度下降,而是每次随机选取一个误分类点使其梯度下降(随机梯度法),如3中的 ( x i , y i ) (x_i,y_i) (xi,yi)这一误分类点
      • 如果 ( x i , y i ) (x_i,y_i) (xi,yi)是误分类点,说明 y i 、 f ( x i ) y_i、f(x_i) yif(xi)异号,则如3中满足 y i ( w ⋅ x i + b ) ⩽ 0 y_i(w\cdot x_i+b)\leqslant 0 yi(wxi+b)0
      • 梯度可以由上面损失函数的数学形式看出
    • 步骤4:

      步骤4可能是算法中最不好理解的地方,我学到这里的疑问是:

      用上面的步骤为什么能实现”直至训练集中没有误分类点“?

      这里其实涉及到一个普遍且重要的问题——算法的收敛性,换句话说,我们的算法有效的话,那么经过有限次修正之后一定能找到符合终止条件的模型。

      证明请见:Novikoff定理证明

4、算法——对偶形式

对偶形式的基本思想是将 w w w b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数而求得 w w w b b b

原始形式中对误分类点 ( x i , y i ) (x_i,y_i) (xi,yi)通过:

w ← w + η y i x i b ← b + η y i w\leftarrow w+\eta y_ix_i \\ b\leftarrow b+\eta y_i ww+ηyixibb+ηyi

来修正。假设对于某误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),一共修正了 n i n_i ni次,那么:

w ← w + n i η y i x i b ← b + n i η y i w\leftarrow w+n_i\eta y_ix_i \\ b\leftarrow b+n_i\eta y_i ww+niηyixibb+niηyi

那么,对于所有数据点 w , b w,b w,b的变化就是:

w ← w + ∑ i = 1 N n i η y i x i b ← b + ∑ i = 1 N n i η y i w\leftarrow w+\sum_{i=1}^{N} n_i\eta y_ix_i \\ b\leftarrow b+\sum_{i=1}^{N}n_i\eta y_i ww+i=1Nniηyixibb+i=1Nniηyi

如果令初始 w 0 = 0 , b 0 = 0 , α i = n i η w_0=0,b_0=0,\alpha_i = n_i\eta w0=0,b0=0,αi=niη,则有:

w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w=\sum_{i=1}^{N} \alpha_i y_ix_i \\ b=\sum_{i=1}^{N}\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

在原始形式中,我们是要学习 w , b w,b w,b,现在可以转化为 α 、 b \alpha 、b αb

对偶形式:

  • 输入:

    T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } x i ∈ X = R n , y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N ; 0 < η ⩽ 1 T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\}\\ x_i\in {X}=\bf{R}^n , y_i\in {Y} =\{-1,+1\}, i=1,2,\dots, N; 0< \eta \leqslant 1 T={ (x1,y1),(x2,y2),,(xN,yN)}xiX=Rn,yiY={ 1,+1},i=1,2,,N;0<η1

  • 输出:

    α , b ; f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) α = ( α 1 , α 2 , . . . α N ) T \alpha ,b; f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b)\\\alpha=(\alpha_1,\alpha_2,...\alpha_N)^T α,b;f(x)=sign(j=1Nαjyjxjx+b)α=(α1,α2,...αN)T

  • 步骤:

    1. α ← 0 , b ← 0 \alpha \leftarrow 0,b\leftarrow 0 α0,b0

    2. 训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)

    3. 如果 y i ( ∑ j = 1 N α j y j x j ⋅ x + b ) ⩽ 0 y_i\left(\sum_{j=1}^N\alpha_jy_jx_j\cdot x+b\right) \leqslant 0 yi(j=1Nαjyjxjx+b)0

      α i ← α i + η b ← b + η y i \alpha_i\leftarrow \alpha_i+\eta \\b\leftarrow b+\eta y_i αiαi+ηbb+ηyi

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

  • 步骤解释:

    • 步骤1:和前面一样,初始值取0

    • 步骤2:每次也是选取一个数据

    • 步骤3:

      • 如果数据点是误判点的话,开始修正
      • 这里关注一下梯度的计算:对于每一个数据 ( x i , y i ) (x_i,y_i) (xi,yi)每一次修正来说, α i \alpha_i αi的变化量是: η \eta η b b b还是 η y i \eta y_i ηyi不变
    • 步骤4:与原始形式一样,感知机学习算法的对偶形式迭代是收敛的,存在多个解

Gram matrix

对偶形式中,训练实例仅以内积的形式出现。

为了方便可预先将训练集中的实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram矩阵

G = [ x i ⋅ x j ] N × N G=[x_i\cdot x_j]_{N\times N} G=[xixj]N×N

三、代码实现

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

#加载数据
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'
]
print(df.label.value_counts())

#画出原始数据离散图
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0')
plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('original data')
plt.legend()
plt.show()

data = np.array(df.iloc[:100, [0, 1, -1]])
X, y = data[:,:-1], data[:,-1]
print("X: ",X)
print("y: ",y)
y = np.array([1 if i == 1 else -1 for i in y])

#感知机模型
# 数据线性可分,二分类数据
# 此处为一元一次线性方程
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)

#画出训练结果
x_points = np.linspace(4, 7, 10)
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.title('result')
plt.legend()
plt.show()

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SSYuQ3Zn-1636977903383)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d3b23003-63be-495a-bbb9-ba3b3a16a9ec/Untitled.png)]

习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual

你可能感兴趣的:(人工智能,机器学习,支持向量机,分类)