Loading...
墨滴

blue吖

2021/09/12  阅读:35  主题:前端之巅同款

机器学习算法——感知机

1.前言


​感知机在1957年由Rosenblatt提出,是支持向量机和神经网络的基础。感知机是一种二类分类的线性分类模型,输入为实例的特征向量,输出为实例的类别,正类取1,负类取-1。感知机是一种判别模型,其目标是求得一个能够将数据集中的正实例点和负实例点完全分开的分离超平面。如果数据不是线性可分的,则最后无法获得分离超平面。

2.模型


假设模型的输入为 ,输出为{+1,-1},则模型可以表示为:

其中 为感知机的模型参数, 即为要求的分离超平面。图1为感知机模型的示意图, 即为一个超平面。

图1 感知机模型
图1 感知机模型

感知机学习时,由训练数据集 ,其中 , , ,求得感知机模型 。感知机预测时,通过训练好的 判别新的输入实例的类别。

3.损失函数


为了求得分离超平面,需要构建一个损失函数,并通过极小化此损失函数来求得模型参数

感知机的损失函数为所有误分类点到超平面的距离之和。首先写出输入空间 任一实例点到 分离超平面的距离 ,即图2中的红线长度:

图2 实例点到超平面的距离
图2 实例点到超平面的距离

即为向量 在超平面的单位法向量 上的投影长度,则距离的表达式可以写为:

当正类误分类为负类时,即当 时,有

当负类误分类为正类时,即当 时,有 。所以,误分类点到超平面的距离为:

假设误分类点的集合为M,则所有误分类点到超平面的距离总和为:

不考虑 ,就得到了感知机的损失函数:

4.感知机的学习算法


要求得模型参数 ,需要极小化损失函数,即:

极小化的过程采用随机梯度下降算法(stochastic gradient descent, SGD)来实现,首先任意选取一个超平面 ,然后找出误分类点,每次随机选取一个误分类点来进行梯度下降,进而对 进行更新,直到没有误分类点:

其中, 为学习率。

4.1 感知机学习算法的原始形式

  • 输入: 训练数据集 , 其中 , , ,学习率

  • 输出: ; 感知机模型

  • 算法流程:

    1. 选取初值:
    2. 在训练集中选取数据
    3. 如果 ,
    4. 转至第2步,直至训练集中没有误分类点。
  • 图3为李航《统计学习方法》中的例子。

图 3 感知机学习算法原始形式示例
图 3 感知机学习算法原始形式示例

4.2 感知机学习算法的对偶形式

对偶形式的基本想法是,将 表示为实例 和标记 的线性组合形式。设误分类点 通过梯度下降算法对 修改了 次,则 关于 的增量分别为 ,这里的 。则最后学习到的 可以分别表示为:

  • 输入: 训练数据集 , 其中 , , ,学习率
  • 输出: ;感知机模型 ,其中, ,一般初值 取0。
  • 算法流程:
    1. 选取初值: ;
    2. 在训练集中选取数据
    3. 如果 ,
    4. 转至第2步,直至没有误分类数据。
  • 图4为李航《统计学习方法》中的例子。
图4 感知机学习算法对偶形式示例
图4 感知机学习算法对偶形式示例

5.代码实现


本文实现了感知机学习算法的原始形式,使用的数据集为iris数据集,数据集大小为150×5,前4列为特征,最后一列为标签,共有三种类别,每种类别有50行数据;由于感知机为二分类模型,所以这里只使用了前100行数据作为训练数据,并且选择sepal_length,sepal_width作为特征来进行训练,代码实现是在jupyter notebook中完成的,实现过程如下:

  • 导入需要使用的包
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
  • 加载并处理数据

加载数据:

iris = sns.load_dataset("iris")
iris.head() //打印数据前5
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa

选择前100行数据:

df = iris.iloc[:100,[01-1]]
df
sepal_length sepal_width species
0 5.1 3.5 setosa
1 4.9 3.0 setosa
2 4.7 3.2 setosa
3 4.6 3.1 setosa
4 5.0 3.6 setosa
... ... ... ...
95 5.7 3.0 versicolor
96 5.7 2.9 versicolor
97 6.2 2.9 versicolor
98 5.1 2.5 versicolor
99 5.7 2.8 versicolor

100 rows × 3 columns

标签编码:将标签变为0,1,2样式
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
df["species"] = encoder.fit_transform(df["species"])

此时,可以画出将数据进行可视化,代码如下,可视化结果如图5所示:

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.legend()
图5 数据可视化
图5 数据可视化

划分训练集与测试集:

from sklearn.model_selection import train_test_split

data = np.array(df)  
X, y = data[:,:-1], data[:,-1]  
y = np.array([1 if i == 1 else -1 for i in y])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)  
  • 算法的实现
class Model:
    def __init__(self):
        #初始化w, b和学习率
        self.w = np.ones(2, dtype=np.float32)     
        self.b = 0 
        self.l_rate = 0.01     
        
    def multiply(self, x, w, b):
        y = np.dot(x, w) + b      
        return y
    
    #模型训练,随机梯度下降
    def model_fit(self, X_train, y_train):
        print("start to fit")
        flag = True
        while flag:
            wrong_count = 0
            for i in range(len(X_train)):
                X = X_train[i]
                y = y_train[i]
                if y * self.multiply(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:
                flag = False
        print("Model training completed!")
        print("w = {}, b = {}".format(self.w, self.b))  #给出训练后的模型参数
    
    #模型测试,给出正确率
    def model_test(self, X_test, y_test):
        print("start to test")
        m = X_test.shape[0]
        errorCnt = 0
        for i in range(m):
            X = X_test[i]
            y = y_test[i]
            if y * self.multiply(X, self.w, self.b) <= 0:
                errorCnt += 1
        accruRate = 1 - (errorCnt / m)
        print("Model testing completed!")
        print("Accuracy rate is {}".format(accruRate))

perceptron = Model()
perceptron.model_fit(X_train, y_train)
perceptron.model_test(X_test, y_test)

  • 实验结果
图6 实验结果及可视化
图6 实验结果及可视化

6.参考资料


  1. 李航《统计学习方法》
  2. https://github.com/Dod-o/Statistical-Learning-Method_Code
  3. https://github.com/fengdu78/lihang-code

blue吖

2021/09/12  阅读:35  主题:前端之巅同款

作者介绍

blue吖