口袋算法的示例
原理
口袋算法是感知器(Perceptron)算法的一种改进。感知器算法是一种线性分类算法,但在训练数据不是线性可分的情况下,它可能无法收敛,即无法找到一个线性分类器来正确分类所有的训练样本。为了解决这个问题,口袋算法引入了一个"口袋"(Pocket),用来存储迄今为止最好的权重向量(即使它不能正确分类所有样本,但错误率最低)。
口袋算法的基本思想是:
- 初始化权重向量。
- 在每次迭代中,随机选择一个误分类样本。
- 根据这个样本更新权重向量。
- 如果更新后的权重向量比当前最佳的权重向量更好(即误分类样本更少),则将其存入"口袋"中。
- 继续迭代直到达到预定的最大迭代次数或连续若干次迭代不再更新最佳权重向量。
作用
口袋算法的作用是改进感知器算法,使其能够在训练数据非线性可分的情况下仍然能够找到一个尽可能好的线性分类器。它能够在一定程度上减少误分类的样本数,提高分类器的准确性。
口袋算法步骤
-
初始化:
-
迭代:
-
终止条件:
- 达到预定的最大迭代次数。
- 连续若干次迭代不再更新最佳权重向量。
数学原理推导过程
口袋算法(Pocket Algorithm)是感知器算法的一种改进版本。它旨在解决感知器算法在处理非线性可分数据集时可能无法收敛的问题。口袋算法引入了一个“口袋”来存储迄今为止最好的权重向量,以确保即使在数据集不可线性分的情况下,算法也能找到一个尽可能好的线性分类器。
口袋算法的改进
口袋算法在感知器算法的基础上引入了一个“口袋”,用于存储迄今为止最好的权重向量。具体步骤如下:
3. 终止条件:
- 达到预定的最大迭代次数。
- 连续若干次迭代不再更新最佳权重向量。
数学推导
感知器学习算法(PLA)
感知器学习算法(PLA,Perceptron Learning Algorithm)是机器学习中的一种基础算法,专用于处理二分类问题。它的目标是找到一条能够线性分割两个类别的超平面。
PLA的关键概念
-
线性可分:
- PLA假设数据是线性可分的,即存在一个超平面能够将两个类别的数据完全分开。
-
算法步骤:
- PLA从初始权重开始,通常设置为零向量。
- 遍历训练数据,对每个样本进行分类,如果分类错误,则更新权重。
- 更新规则是简单的:对于一个分类错误的样本,按照样本的特征向量和标签的乘积进行更新。
-
更新规则:
- 权重更新规则可以表示为:
-
收敛性:
- 如果数据是线性可分的,PLA保证能找到一个超平面正确分类所有训练数据。
- 如果数据不是线性可分的,PLA可能永远不会收敛。
PLA与口袋算法
口袋算法是PLA的扩展,设计用来处理线性不可分的数据。其关键思想是保持(或放入口袋)迄今为止找到的最佳解决方案,即使当前权重向量不能完美分类所有数据,也会保留错误最少的那个。
PLA的例子
以下是PLA的一个简化版本的实现:
import numpy as npdef perceptron_learning_algorithm(X, y):"""感知器学习算法实现。注意:该算法仅适用于线性可分的数据集。对于不可线性分的数据集,算法可能不会收敛。参数:X (ndarray): 训练数据特征,形状为 (样本数, 特征数)y (ndarray): 目标标签,形状为 (样本数,)返回值:ndarray: 学习到的权重系数,形状为 (特征数,)"""# 初始化变量done = FalseW = np.zeros(X.shape[1]) # 初始化权重系数为零# 迭代直到收敛while not done:done = True# 遍历训练数据中的每个样本for index in range(len(X)):x = X[index]# 检查当前样本是否被错误分类if np.dot(x, W) * y[index] <= 0:done = False# 更新权重系数W += y[index] * xreturn W# 示例用法:
if __name__ == "__main__":# 示例数据:二维点及其标签X = np.array([[2, 3], [4, 5], [1, 8], [6, 2], [7, 3]])y = np.array([1, 1, -1, -1, 1])# 运行感知器学习算法W = perceptron_learning_algorithm(X, y)# 输出学习到的权重系数print("Learned weights:", W)
运行结果
Learned weights: [10. 4.]
结果解释
-
初始权重: 程序首先将权重向量
W
初始化为零向量,即[0, 0]
。这意味着在开始时,算法没有任何偏向性。 -
遍历样本: 在每次迭代中,算法遍历所有样本,检查每个样本是否被正确分类。
-
更新权重: 如果发现某个样本被错误分类(即当前权重
W
无法正确分类该样本),则算法会更新权重。更新公式为:
4. 收敛: 当所有样本都被正确分类时,算法停止迭代,并返回最终的权重向量。
权重向量 [10, 4]
的含义
- 学习到的权重向量
[10, 4]
表示一个直线决策边界,能够将样本点正确地线性分割为两类。 - 在二维平面中,直线的方程为:
这条直线将样本空间分为两部分,使得每个部分包含相应类别的样本点。
总结
- 感知器学习算法通过反复调整权重,找到一个线性决策边界,使得所有样本点都被正确分类。
- 该算法对于线性可分的数据集非常有效,但对于不可线性分的数据集可能不会收敛。
感知器学习算法演示
import numpy as npdef perceptron_learning_algorithm_with_history(X, y):"""感知器学习算法实现,带有权重历史记录。注意:该算法仅适用于线性可分的数据集,对于线性不可分的数据集,该函数将不会收敛。参数:X (ndarray): 训练数据特征,形状为 (样本数, 特征数)y (ndarray): 目标标签,形状为 (样本数,)返回:ndarray: 权重系数历史记录数组,形状为 (迭代次数, 特征数)list: 误分类样本的索引列表"""done = FalseW = np.zeros(X.shape[1]) # 初始化权重系数为零weight_history = np.array([W]) # 数组用于存储权重系数的历史记录error_indices = [] # 列表用于存储误分类样本的索引while not done:done = Truefor index in range(len(X)): # 遍历训练数据中的每一个样本x = X[index]if np.dot(x, W) * y[index] <= 0: # 检查当前样本是否被误分类done = FalseW = W + y[index] * x # 更新权重系数weight_history = np.append(weight_history, [W], axis=0) # 将更新后的权重系数添加到历史记录error_indices.append(index) # 记录误分类样本的索引return weight_history, error_indices# 示例代码
if __name__ == "__main__":# 生成示例数据:带标签的二维点X = np.array([[2, 3], [4, 5], [1, 8], [6, 2], [7, 3]])y = np.array([1, 1, -1, -1, 1])# 运行感知器学习算法weight_history, error_indices = perceptron_learning_algorithm_with_history(X, y)# 输出学习到的权重系数和误分类样本的索引print("权重历史记录:\n", weight_history)print("误分类样本的索引:\n", error_indices)
结果与解释
假设示例数据如下:
特征值 (X):
[[2, 3],[4, 5],[1, 8],[6, 2],[7, 3]]
目标标签值 (y):
[ 1, 1, -1, -1, 1]
运行算法后,可能得到以下输出:
权重历史记录:[[ 0. 0.][ 2. 3.][ 1. 11.][-5. -3.]]
误分类样本的索引:[0, 2, 3]
解释:
- 初始权重系数为 [0, 0]。
- 第一次更新后权重系数变为 [2, 3]。
- 第二次更新后权重系数变为 [1, 11]。
- 第三次更新后权重系数变为 [-5, -3]。
误分类样本的索引表示在训练过程中被误分类的样本在数据集中的位置。通过权重历史记录,可以观察到权重的更新过程和算法的收敛情况。
参考:
文献一、https://github.com/lawlite19/MachineLearning_Python
文献二、https://github.com/Jack-Lee-Hiter/AlgorithmsByPython
文献三、https://github.com/zkywsg/Daily-DeepLearning?tab=readme-ov-file
文献四、https://github.com/MemorialCheng/deep-learning-from-scratch
文献五、https://github.com/shunliz/Machine-Learning
文献六、https://github.com/Saisimon/AIMindMap/tree/main/machine-learning