概念:感知机 (perceptron) 是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,取+1和-1二值。感知机对应于输入空间(特征空间)中将实例划 分为正负两类的分离超平面,属于判别模型。感知机学习旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型。感知机学习算法具有简单而易于实现的优点,分为原始形式和对偶形式。感知机预测是用学习得到的感知机模型对新的输入实例进行分类。
目录
1.感知机模型
定义(感知机) 假设输入空间(特征空间)是, 输出空间是 y={+1,-1}。 输入 x∈X 表示实例的特征向量,对应于输入空间(特征空间)的点; 输出y∈Y 表示实例的类别。由输入空间到输出空间的如下函数:
f(x)=sign(w·x+b)
称为感知机。其中,w 和 b 为感知机模型参数, w ∈Rn 叫作权值(weight) 或权值向 量(weight vector),b∈R叫作偏置(bias),w·x 表示w 和x 的内积。sign 是符号 函数,即
感知机是一种线性分类模型,属于判别模型。感知机模型的假设空间是定义在 特征空间中的所有线性分类模型 (linear classification model) 或线性分类器 (linear classifier),即函数集合
{f|f(a)=w ·x+b}。线性方程:
2.感知机策略
2.1数据集的线性可分
如果存在某个超平面能够将数据集的正实例点和负实例点完全正确地划分到超平面的两侧,即对所有Wi=+1 的实例i, 有 w·x;+b>0,对所有yi=-1的实例i, 有 w·x;+b<0,则称数据集T 为线性可分数据集(linearly separable data set); 否则,称数据集T 线性 不可分。就是不同的实例点能用一条线分开。
2.2感知机学习策略
假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练集正实 例点和负实例点完全正确分开的分离超平面。为了找出这样的超平面,即确定感知 机模型参数 w,b, 需要确定一个学习策略,即定义(经验)损失函数并将损失函数极小化。
感知机模型的损失函数是基于误分类点到决策边界的距离。具体来说,感知机的损失函数定义为所有误分类点的总损失。为此,首先写出输入空间R中任一点xo 到超平面 S 的距离:
![](https://i-blog.csdnimg.cn/blog_migrate/a8a159123b5792f9cd36f02087628f79.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f7f9e96daa473c6d7b188164c9b5b416.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c24c2071e8b0c2dc3d38f9455bbf9dbb.png)
损失函数为: M为误分类点的数目
损失函数的理解
- 针对误分类:这个损失函数只考虑那些被误分类的样本。如果一个样本被正确分类,它对损失函数的贡献为零。
- 距离的角色:损失函数实际上是对误分类样本到决策边界的距离的一个度量。对于线性方程 w⋅x+b=0,点 xi 到这个决策边界的距离与 ∣w⋅xi+b∣ 成正比。
- 符号和直观含义:当一个样本被误分类时,yi 和 w⋅xi+b 的符号相反,所以 )−yi(w⋅xi+b) 是正的。这意味着损失函数是将所有误分类样本到决策边界的距离相加。
损失函数的选择原因
- 简单有效:这种形式的损失函数非常简单,易于计算和理解。
- 直接关联错误:它直接与模型的错误分类数量相关联,使得优化过程直接针对减少错误分类。
- 梯度友好:这个损失函数对于权重和偏置是线性的,这使得在使用梯度下降法优化时计算梯度变得简单。
3.感知机算法
感知机学习问题转化为求解损失函数式的最优化问题,最优化的方法是随 机梯度下降法。本节叙述感知机学习的具体算法,包括原始形式和对偶形式,并证明 在训练数据线性可分条件下感知机学习算法的收敛性。
3.1 感知机学习算法的原始形式
感知机学习算法是对以下最优化问题的算法。给定一个训练数据集
T={(x₁,yi),(xz,y₂),…,(xn,yn)}
其中,x;∈X=Rn,y;∈Y={-1,1} ,i=1,2,…,N, 求参数w,b,使其为以下损
失函数极小化问题的解
其中 M 为误分类点的集合。
感知机学习算法是误分类驱动的,具体采用随机梯度下降法(stochastic gradientdescent) 。 首先,任意选取一个超平面w0,b0, 然后用梯度下降法不断地极小化目标 函数。极小化过程中不是一次使M 中所有误分类点的梯度下降,而是一次随机 选取一个误分类点使其梯度下降。
假设误分类点集合M 是固定的,那么损失函数L(w,b) 的梯度由
给出。
随机选取一个误分类点(xi,yi), 对 w,b 进行更新:
w ←w+ηyiTi (2.6)
b-b+ηyi (2.7)
式中η(O<η≤1) 是步长,在统计学习中又称为学习率(learning rate)。这样,通过 迭代可以期待损失函数L(w,b) 不断减小,直到为0。综上所述,得到如下算法:
算法2.1(感知机学习算法的原始形式)
输入:训练数据集T={(xi,3n),(xz,y₂),…,(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)如果y₁(w·xi+b)≤0,
w=w+ηyiT
b=b+ηyi
(4)转至(2),直至训练集中没有误分类点。
代码分析步骤如下:
首先准备训练的数据集
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris # 加载鸢尾花数据集
import matplotlib.pyplot as plt
# 假设这里已经载入了鸢尾花数据集到df
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
# 为数据帧的列重命名,以便更好地阅读
df.label.value_counts()
# 计算'label'列中每个唯一值的数量,这有助于查看数据集中不同物种的分布情况
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')
# 为花萼长度和宽度创建散点图。
# 第一个图是前50个条目(假设这些是类型'0'),
# 第二个图是接下来的50个条目(假设这些是类型'1')。
plt.xlabel('sepal length')
plt.ylabel('sepal width')
# 设置x轴和y轴的标签
plt.legend()
# 添加图例以区分两个散点图
#plt.show()
# 这会显示绘制的图形。它被注释掉了,所以不会执行。
data = np.array(df.iloc[:100, [0, 1, -1]])
# 选择数据帧的前100行以及第1、2和最后一列,并将其转换为NumPy数组。
# 这可能是为了专注于两个物种(每个代表50个样本)。
X, y = data[:,:-1], data[:,-1]
# 将数据分为特征(X)和标签(y)。
# 特征是'花萼长度'和'花萼宽度',而标签是物种类型。
y = np.array([1 if i == 1 else -1 for i in y])
# 将物种标签转换为二进制形式,物种'1'为1,其他物种为-1。
鸢尾花数据集的前几行如下所示:
| | sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | label |
|----|-------------------|------------------|-------------------|------------------|-------|
| 0 | 5.1 | 3.5 | 1.4 | 0.2 | 0 |
| 1 | 4.9 | 3.0 | 1.4 | 0.2 | 0 |
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | 0 |
| 3 | 4.6 | 3.1 | 1.5 | 0.2 | 0 |
| 4 | 5.0 | 3.6 | 1.4 | 0.2 | 0 |
在这个数据集中,每一行代表一朵鸢尾花的测量数据,包括:
- 花萼长度(cm)
- 花萼宽度(cm)
- 花瓣长度(cm)
- 花瓣宽度(cm)
- 标签(label):表示鸢尾花的种类,用0、1、2的数字来表示不同的种类。
-
选择数据:鸢尾花数据集包含三个类别,但感知机是二分类模型,因此需要选择其中的两个类别(例如,Iris Setosa 和 Iris Versicolour)。通常选用花萼长度和宽度作为特征。
-
预处理数据:
- 从数据集中选取所需的特征和标签。
- 将标签转换为感知机算法所需的形式,比如将一个类别标记为+1,另一个标记为-1。
算法过程:
-
初始化:设定权重 w 和偏置 b 初始值,通常为0或小随机数。
-
训练:对于每个训练样本 (xi,yi),按如下规则更新 w 和 b:
如果 yi⋅(w⋅xi+b)≤0 (意味着样本被误分类),则更新:
w=w+ηyixi b=b+ηyi
其中,η 是学习率,是一个固定的小正数。
-
重复:重复步骤2,直到所有样本正确分类或达到一定迭代次数。
举例:
假设我们有以下二维数据(特征为 x1,x2,标签为 y):
- x1=[1,2],y1=1
- x2=[2,3],y2=−1
初始化 w=[0,0] 和b=0,学习率 η=1。
-
对于 x1,y1⋅(w⋅x1+b)=1⋅([0,0]⋅[1,2]+0)=0。因为 0≤0,
-
我们更新w 和 b:w=[0,0]+1⋅1⋅[1,2]=[1,2] ,b=0+1⋅1=1
-
接着对于 y2⋅(w⋅x2+b)=−1⋅([1,2]⋅[2,3]+1)=−1⋅(8+1)=−9。因为 −9≤0,我们再次更新 w 和 b:
w=[1,2]+1⋅−1⋅[2,3]=[−1,−1] ,b=1+1⋅−1=0
# 定义一个感知机模型类
class Model:
def __init__(self):
# 初始化权重w为全1向量,长度与数据特征数量相同(除去标签)
self.w = np.ones(len(data[0]) - 1, dtype=np.float32)
# 初始化偏置b为0
self.b = 0
# 设置学习率为0.1
self.l_rate = 0.1
# 定义符号函数,用于计算数据点x与当前权重和偏置的线性组合
def sign(self, x, w, b):
y = np.dot(x, w) + b
return y
# 使用随机梯度下降法进行训练
def fit(self, X_train, y_train):
is_wrong = False
count = 1
# 当还有误分类点时,继续迭代
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
# 打印当前的权重和偏置
print(f"更新第{count}后的权重: {self.w}, 偏置: {self.b}")
count += 1
# 如果没有误分类点,结束迭代
if wrong_count == 0:
is_wrong = True
return 'Perceptron Model!'
# 定义模型评分方法(这里尚未实现)
def score(self):
pass
# 实例化感知机模型
perceptron = Model()
# 使用训练数据(X, y)训练模型
perceptron.fit(X, y)
# 创建一个等差数列,用于绘制决策边界的x坐标。范围从4到7,共10个点。
x_points = np.linspace(4, 7, 10)
# 计算对应的y坐标,以绘制决策边界。这里使用感知机模型的权重和偏置。
y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1]
# 绘制决策边界
plt.plot(x_points, y_)
# 绘制数据点,蓝色点代表类别0,橙色点代表类别1。
# 这里假设data的前50个样本属于类别0,接下来的50个样本属于类别1。
plt.plot(data[:50, 0], data[:50, 1], 'bo', label='0') # 使用'bo'表示蓝色圆圈
plt.plot(data[50:100, 0], data[50:100, 1], 'o', color='orange', label='1') # 使用'o'和color参数表示橙色圆圈
#
# # 设置x轴和y轴的标签
plt.xlabel('sepal length')
plt.ylabel('sepal width')
# 添加图例
plt.legend()
plt.show()