感知机原理解析 & python代码实现

本文深入解析感知机的工作原理,介绍了由两层神经元组成的简单模型,详细阐述了其数学表达与损失函数的推导过程。通过使用Python语言,实现了感知机的训练与预测功能,展示了在鸢尾花数据集上的应用效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文总结了感知机的基本原理,并给出了python的实现代码。

参考:

  1. 《机器学习》 周志华
  2. https://github.com/datawhalechina/pumpkin-book   这个项目补全了周志华《机器学习》中省略的公式推导过程

1、感知机原理

感知机(Perceptron)由两层神经元组成,输入层接收输入,输出层是M-P神经元(又称阈值逻辑单元threshold logic unit),计算公式为:
y=f(\sum_{i=1}^n(w_ix_i-\theta))
上式中的激活函数f()可以选择阶跃函数或者sigmoid函数,w_i是输入的第i个分量和输出神经元之间的连接权值。将前面公式中的\theta当作哑节点,公式可以写成:

y=f(w^Tx)

损失函数为:

L(w)=\sum_{x_i\in M}(\hat{y}_i-y_i)w^Tx

其中M是分类错误的样本集,从上式可以看出,当样本分类正确的时候,损失为0。损失函数的梯度为:

\bigtriangledown L(w)=\sum_{x_i\in M}(\hat{y}_i-y_i)x_i

因此梯度下降更新权重:

w=w-\eta\bigtriangledown L(w)=w+\eta(y_i-\hat{y}_i)x_i

2、python实现

代码如下

# -*- coding:utf-8 -*-
# author: dtf320

"""单层感知机"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

class SinglePerceptron:
    def __init__(self,eta=0.1,epoch=100):
        self.eta = eta
        self.epoch = epoch

    def add_dummy_node(self,X):
        """
        增加哑变量

        :param X: [n_samples,n_features]
        :return:
        """

        return np.column_stack((X,-1*np.ones(shape=(X.shape[0],1))))

    def sgn(self,mat):
        """
        处理矩阵中的每一个数

        :param mat: 矩阵
        :return:
        """
        d = np.array(mat)
        fun = lambda x:0 if x<=0 else 1
        r = map(fun,np.array(d).flat)
        return np.array(list(r)).reshape(d.shape)

    def fit(self,X,Y):
        """

        :param X: [n_samples,n_features]
        :param Y: [n_samples,dim_output]
        :return:
        """
        self.X = np.array(X)
        self.X = self.add_dummy_node(self.X)  # 增加哑变量dummy node
        self.Y = np.array(Y)
        self.n_samples = self.X.shape[0]
        self.n_features = self.X.shape[1]
        self.dim_output = self.Y.shape[1]

        self.W1 = np.random.randn(self.dim_output,self.n_features)
        # Yest = self.sgn(np.dot(self.W1,self.X.T))  # Y_est [dim_output,n_samples]

        for j in range(self.epoch):
            for i in range(self.n_samples):
                X_ = self.X[i,:].reshape(1,self.n_features)
                Y_ = self.Y[i,:].reshape(self.dim_output,1)
                Yest = self.sgn(np.dot(self.W1,X_.T))
                E_y = Y_.T - Yest  # E_y [dim_output,n_samples]
                delta_w = self.eta * np.dot(E_y, X_)
                self.W1 += delta_w
                print("epoch", j, "iter",i,"weight",self.W1)

    def prediction(self,X_in):
        X_in = np.array(X_in)
        X_in = self.add_dummy_node(X_in)
        res = self.sgn(np.dot(self.W1,X_in.T))
        return res.reshape(-1,1)

    def drawing_edge(self,x_range):
        y = []
        x = np.arange(x_range[0],x_range[1],0.1)
        for cx in x:
            y_ = (self.W1[0][2]-self.W1[0][0]*cx) / self.W1[0][1]
            y.append(y_)
        y = np.array(y)
        plt.plot(x, y)
        negative_idx = np.where(Y == 0)[0]
        positive_idx = np.where(Y == 1)[0]
        for i in negative_idx:
            p1 = plt.scatter(X[i, 0], X[i, 1], c="r")
        for i in positive_idx:
            p2 = plt.scatter(X[i, 0], X[i, 1], c="g")
        plt.legend([p1,p2],["Setosa","Versicolour"])
        plt.show()


if __name__ == "__main__":
    from sklearn import datasets
    X,Y = datasets.load_iris(return_X_y=True)  # 安德森鸢尾花数据集
    Y = Y.reshape(-1,1)
    # 数据集中总共有150个样本,分别为50个山鸢尾(Setosa)样本,
    # 50个变色鸢尾(Versicolour)样本,50个维吉尼亚鸢尾(Virginica)样本
    # 这里选取前两个品种共100个样本
    X = X[0:100,:]
    Y = Y[0:100,:]
    # 数据集中每个样本有4个字段, [花萼长度, 花萼宽度, 花瓣长度, 花瓣宽度]
    # 这里选择花萼宽度和花瓣长度两个字段
    X = X[:, [1, 2]]

    X_train, X_test, Y_train, Y_test = train_test_split(X,Y,test_size=0.3,stratify=Y)  # 分层采样
    model = SinglePerceptron(eta=0.1,epoch=10)
    model.fit(X_train, Y_train)
    y_pred = model.prediction(X_test)
    acc = accuracy_score(Y_test,y_pred)
    print("*"*30)
    print("Number of train samples:",len(X_train))
    print("Number of test samples:",len(X_test))
    print("Accuracy:",acc)
    model.drawing_edge([1, 5])

结果如下所示:
Number of train samples: 70
Number of test samples: 30
Accuracy: 1.0
图中的蓝色线条是感知机计算出的两类分界线。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值