2023国赛数学建模思路 - 案例:感知机原理剖析及实现

2023-10-27

# 0 赛题思路

(赛题出来以后第一时间在CSDN分享)

https://blog.csdn.net/dc_sinor?type=blog

1 感知机的直观理解

感知机应该属于机器学习算法中最简单的一种算法,其原理可以看下图:

在这里插入图片描述

比如说我们有一个坐标轴(图中的黑色线),横的为x1轴,竖的x2轴。图中的每一个点都是由(x1,x2)决定的。如果我们将这张图应用在判断零件是否合格上,x1表示零件长度,x2表示零件质量,坐标轴表示零件的均值长度和均值重量,并且蓝色的为合格产品,黄色为劣质产品,需要剔除。那么很显然如果零件的长度和重量都大于均值,说明这个零件是合格的。也就是在第一象限的所有蓝色点。反之如果两项都小于均值,就是劣质的,比如在第三象限的黄色点。

在预测上很简单,拿到一个新的零件,我们测出它的长度x1,质量x2,如果两项都大于均值,说明零件合格。这就是我们人的人工智能。

那么程序怎么知道长度重量都大于均值的零件就是合格的呢?
或者说

它是怎么学会这个规则的呢?
程序拿到手的是当前图里所有点的信息以及标签,也就是说它知道所有样本x的坐标为(x1, x2),同时它属于蓝色或黄色。对于目前手里的这些点,要是能找到一条直线把它们分开就好了,这样我拿到一个新的零件,知道了它的质量和重量,我就可以判断它在线的哪一侧,就可以知道它可能属于好的或坏的零件了。例如图里的黄、蓝、粉三条线,都可以完美地把当前的两种情况划分开。甚至x1坐标轴或x2坐标轴都能成为一个划分直线(这两个直线均能把所有点正确地分开)。

读者也看到了,对于图中的两堆点,我们有无数条直线可以将其划分开,事实上我们不光要能划分当前的点,当新来的点进来是,也要能很好地将其划分,所以哪条线最好呢?

怎样一条直线属于最佳的划分直线?实际上感知机无法找到一条最佳的直线,它找到的可能是图中所有画出来的线,只要能把所有的点都分开就好了。

得出结论:
如果一条直线能够不分错一个点,那就是一条好的直线
进一步来说:

如果我们把所有分错的点和直线的距离求和,让这段求和的举例最小(最好是0,这样就表示没有分错的点了),这条直线就是我们要找的。

2 感知机的数学角度

首先我们确定一下终极目标:甭管找最佳划分直线啥中间乱七八糟的步骤,反正最后生成一个函数f(x),当我们把新的一个数据x扔进函数以后,它会预测告诉我这是蓝的还是黄的,多简单啊。所以我们不要去考虑中间过程,先把结果定了。

在这里插入图片描述

瞧,f(x)不是出来了嘛,sign是啥?wx+b是啥?别着急,我们再看一下sigin函数是什么。

在这里插入图片描述

sign好像很简单,当x大于等于0,sign输出1,否则输出-1。那么往前递归一下,wx+b如果大于等于0,f(x)就等于1,反之f(x)等于-1。

那么wx+b是啥?
它就是那条最优的直线。我们把这个公式放在二维情况下看,二维中的直线是这样定义的:y=ax+b。在二维中,w就是a,b还是b。所以wx+b是一条直线(比如说本文最开始那张图中的蓝线)。如果新的点x在蓝线左侧,那么wx+b<0,再经过sign,最后f输出-1,如果在右侧,输出1。等等,好像有点说不通,把情况等价到二维平面中,y=ax+b,只要点在x轴上方,甭管点在线的左侧右侧,最后结果都是大于0啊,这个值得正负跟线有啥关系?emmm….其实wx+b和ax+b表现直线的形式一样,但是又稍有差别。我们把最前头的图逆时针旋转45度,蓝线是不是变成x轴了?哈哈这样是不是原先蓝线的右侧变成了x轴的上方了?其实感知机在计算wx+b这条线的时候,已经在暗地里进行了转换,使得用于划分的直线变成x轴,左右侧分别为x轴的上方和下方,也就成了正和负。

那么,为啥是wx+b,而不叫ax+b?
在本文中使用零件作为例子,上文使用了长度和重量(x1,x2)来表示一个零件的属性,所以一个二维平面就足够,那么如果零件的品质和色泽也有关系呢?那就得加一个x3表示色泽,样本的属性就变成了(x1,x2,x3),变成三维了。wx+b并不是只用于二维情况,在三维这种情况下,仍然可以使用这个公式。所以wx+b与ax+b只是在二维上近似一致,实际上是不同的东西。在三维中wx+b是啥?我们想象屋子里一个角落有蓝点,一个角落有黄点,还用一条直线的话,显然是不够的,需要一个平面!所以在三维中,wx+b是一个平面!至于为什么,后文会详细说明。四维呢?emmm…好像没法描述是个什么东西可以把四维空间分开,但是对于四维来说,应该会存在一个东西像一把刀一样把四维空间切成两半。能切成两半,应该是一个对于四维来说是个平面的东西,就像对于三维来说切割它的是一个二维的平面,二维来说是一个一维的平面。总之四维中wx+b可以表示为一个相对于四维来说是个平面的东西,然后把四维空间一切为二,我们给它取名叫超平面。由此引申,在高维空间中,wx+b是一个划分超平面,这也就是它正式的名字。

正式来说:
wx+b是一个n维空间中的超平面S,其中w是超平面的法向量,b是超平面的截距,这个超平面将特征空间划分成两部分,位于两部分的点分别被分为正负两类,所以,超平面S称为分离超平面。

细节:

w是超平面的法向量:对于一个平面来说w就是这么定义的,是数学知识,可以谷歌补习一下

b是超平面的截距:可以按照二维中的ax+b理解

特征空间:也就是整个n维空间,样本的每个属性都叫一个特征,特征空间的意思是在这个空间中可以找到样本所有的属性组合

在这里插入图片描述
我们从最初的要求有个f(x),引申到能只输出1和-1的sign(x),再到现在的wx+b,看起来越来越简单了,只要能找到最合适的wx+b,就能完成感知机的搭建了。前文说过,让误分类的点距离和最大化来找这个超平面,首先我们要放出单独计算一个点与超平面之间距离的公式,这样才能将所有的点的距离公式求出来对不?

在这里插入图片描述

先看wx+b,在二维空间中,我们可以认为它是一条直线,同时因为做过转换,整张图旋转后wx+b是x轴,那么所有点到x轴的距离其实就是wx+b的值对不?当然了,考虑到x轴下方的点,得加上绝对值->|wx+b|,求所有误分类点的距离和,也就是求|wx+b|的总和,让它最小化。很简单啊,把w和b等比例缩小就好啦,比如说w改为0.5w,b改为0.5b,线还是那条线,但是值缩小两倍啦!你还不满意?我可以接着缩!缩到0去!所以啊,我们要加点约束,让整个式子除以w的模长。啥意思?就是w不管怎么样,要除以它的单位长度。如果我w和b等比例缩小,那||w||也会等比例缩小,值一动不动,很稳。没有除以模长之前,|wx+b|叫函数间隔,除模长之后叫几何间隔,几何间隔可以认为是物理意义上的实际长度,管你怎么放大缩小,你物理距离就那样,不可能改个数就变。在机器学习中求距离时,通常是使用几何间隔的,否则无法求出解。

在这里插入图片描述
对于误分类的数据,例如实际应该属于蓝色的点(线的右侧,y>0),但实际上预测出来是在左侧(wx+b<0),那就是分错了,结果是负,这时候再加个符号,结果就是正了,再除以w的模长,就是单个误分类的点到超平面的举例。举例总和就是所有误分类的点相加。

上图最后说不考虑除以模长,就变成了函数间隔,为什么可以这么做呢?不考虑wb等比例缩小这件事了吗?上文说的是错的吗?

有一种解释是这样说的:感知机是误分类驱动的算法,它的终极目标是没有误分类的点,如果没有误分类的点,总和距离就变成了0,w和b值怎样都没用。所以几何间隔和函数间隔在感知机的应用上没有差别,为了计算简单,使用函数间隔。

在这里插入图片描述
以上是损失函数的正式定义,在求得划分超平面的终极目标就是让损失函数最小化,如果是0的话就相当完美了。
在这里插入图片描述

感知机使用梯度下降方法求得w和b的最优解,从而得到划分超平面wx+b,关于梯度下降及其中的步长受篇幅所限可以自行谷歌。

3 代码实现

#coding=utf-8
#Author:Dodo
#Date:2018-11-15
#Email:lvtengchao@pku.edu.cn
'''
数据集:Mnist
训练集数量:60000
测试集数量:10000
------------------------------
运行结果:
正确率:81.72%(二分类)
运行时长:78.6s
'''
import numpy as np
import time
def loadData(fileName):
    '''
    加载Mnist数据集
    :param fileName:要加载的数据集路径
    :return: list形式的数据集及标记
    '''
    print('start to read data')
    # 存放数据及标记的list
    dataArr = []; labelArr = []
    # 打开文件
    fr = open(fileName, 'r')
    # 将文件按行读取
    for line in fr.readlines():
        # 对每一行数据按切割福','进行切割,返回字段列表
        curLine = line.strip().split(',')
        # Mnsit有0-9是个标记,由于是二分类任务,所以将>=5的作为1,<5为-1
        if int(curLine[0]) >= 5:
            labelArr.append(1)
        else:
            labelArr.append(-1)
        #存放标记
        #[int(num) for num in curLine[1:]] -> 遍历每一行中除了以第一哥元素(标记)外将所有元素转换成int类型
        #[int(num)/255 for num in curLine[1:]] -> 将所有数据除255归一化(非必须步骤,可以不归一化)
        dataArr.append([int(num)/255 for num in curLine[1:]])
    #返回data和label
    return dataArr, labelArr
def perceptron(dataArr, labelArr, iter=50):
    '''
    感知器训练过程
    :param dataArr:训练集的数据 (list)
    :param labelArr: 训练集的标签(list)
    :param iter: 迭代次数,默认50
    :return: 训练好的w和b
    '''
    print('start to trans')
    #将数据转换成矩阵形式(在机器学习中因为通常都是向量的运算,转换称矩阵形式方便运算)
    #转换后的数据中每一个样本的向量都是横向的
    dataMat = np.mat(dataArr)
    #将标签转换成矩阵,之后转置(.T为转置)。
    #转置是因为在运算中需要单独取label中的某一个元素,如果是1xN的矩阵的话,无法用label[i]的方式读取
    #对于只有1xN的label可以不转换成矩阵,直接label[i]即可,这里转换是为了格式上的统一
    labelMat = np.mat(labelArr).T
    #获取数据矩阵的大小,为m*n
    m, n = np.shape(dataMat)
    #创建初始权重w,初始值全为0。
    #np.shape(dataMat)的返回值为m,n -> np.shape(dataMat)[1])的值即为n,与
    #样本长度保持一致
    w = np.zeros((1, np.shape(dataMat)[1]))
    #初始化偏置b为0
    b = 0
    #初始化步长,也就是梯度下降过程中的n,控制梯度下降速率
    h = 0.0001
    #进行iter次迭代计算
    for k in range(iter):
        #对于每一个样本进行梯度下降
        #李航书中在2.3.1开头部分使用的梯度下降,是全部样本都算一遍以后,统一
        #进行一次梯度下降
        #在2.3.1的后半部分可以看到(例如公式2.6 2.7),求和符号没有了,此时用
        #的是随机梯度下降,即计算一个样本就针对该样本进行一次梯度下降。
        #两者的差异各有千秋,但较为常用的是随机梯度下降。
        for i in range(m):
            #获取当前样本的向量
            xi = dataMat[i]
            #获取当前样本所对应的标签
            yi = labelMat[i]
            #判断是否是误分类样本
            #误分类样本特诊为: -yi(w*xi+b)>=0,详细可参考书中2.2.2小节
            #在书的公式中写的是>0,实际上如果=0,说明改点在超平面上,也是不正确的
            if -1 * yi * (w * xi.T + b) >= 0:
                #对于误分类样本,进行梯度下降,更新w和b
                w = w + h *  yi * xi
                b = b + h * yi
        #打印训练进度
        print('Round %d:%d training' % (k, iter))
    #返回训练完的w、b
    return w, b
def test(dataArr, labelArr, w, b):
    '''
    测试准确率
    :param dataArr:测试集
    :param labelArr: 测试集标签
    :param w: 训练获得的权重w
    :param b: 训练获得的偏置b
    :return: 正确率
    '''
    print('start to test')
    #将数据集转换为矩阵形式方便运算
    dataMat = np.mat(dataArr)
    #将label转换为矩阵并转置,详细信息参考上文perceptron中
    #对于这部分的解说
    labelMat = np.mat(labelArr).T
    #获取测试数据集矩阵的大小
    m, n = np.shape(dataMat)
    #错误样本数计数
    errorCnt = 0
    #遍历所有测试样本
    for i in range(m):
        #获得单个样本向量
        xi = dataMat[i]
        #获得该样本标记
        yi = labelMat[i]
        #获得运算结果
        result = -1 * yi * (w * xi.T + b)
        #如果-yi(w*xi+b)>=0,说明该样本被误分类,错误样本数加一
        if result >= 0: errorCnt += 1
    #正确率 = 1 - (样本分类错误数 / 样本总数)
    accruRate = 1 - (errorCnt / m)
    #返回正确率
    return accruRate
if __name__ == '__main__':
    #获取当前时间
    #在文末同样获取当前时间,两时间差即为程序运行时间
    start = time.time()
    #获取训练集及标签
    trainData, trainLabel = loadData('../Mnist/mnist_train.csv')
    #获取测试集及标签
    testData, testLabel = loadData('../Mnist/mnist_test.csv')
    #训练获得权重
    w, b = perceptron(trainData, trainLabel, iter = 30)
    #进行测试,获得正确率
    accruRate = test(testData, testLabel, w, b)
    #获取当前时间,作为结束时间
    end = time.time()
    #显示正确率
    print('accuracy rate is:', accruRate)
    #显示用时时长
    print('time span:', end - start)

4 建模资料

资料分享: 最强建模资料
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023国赛数学建模思路 - 案例:感知机原理剖析及实现 的相关文章

  • Win32:一个全新的、被忽视的桌面互联网内容平台

    Microsoft 成于Win32 败于Win32 回归Win32 纵观微软的历史 毫无疑问 桌面应用的黄金时代Win32造就了微软庞大的应用生态 进而奠定了曾经的王者 当互联网逐步成为主流的时候 应用生态逐渐发生了变化 这种变化日积月累
  • Ubuntu系统上切换到root用户的多种方法

    在Ubuntu系统上切换到root用户是在进行系统管理和配置时经常需要的操作 通过切换到root用户 您可以获得管理员权限 执行需要特殊权限的任务 在本文中 我们将参考以下文章 https www howtouseubuntu com au
  • 可验证随机函数VRF之Algorand算法

    原文链接 https zhuanlan zhihu com p 29429006 DFINITY的阈值接力结构与可验证随机函数 VRF 密切相关 VRF算法作为一种基于密码学的新型共识模型被提出 最大的优势是快速共识 抗攻击能力 极低算力需
  • Spring boot入门级开发

    现在好多人都是用IDEA开发 好多Spring boot的案例也都是IDEA工程 喜欢用传统Eclipse开发的朋友们就尴住了 那么 小生不才 给大家带来一篇基于Eclipse开发Spring boot的案例 我们都知道Eclipse是一个
  • OpenMVS+Win10+VS2019+vcpkg编译及问题

    Win10 VS2019 OpenMVS1 1 1 Vcpkg 1 VS2019安装 2 git安装 3 vcpkg安装 3 1下载vcpkg 3 2安装vcpkg 3 3 配置环境变量 4 Vcpkg下载OpenMVS依赖的三方库 5 下
  • 【docker】镜像制作build、tag、push至阿里云仓库以及pull

    需要先在阿里云创建镜像服务实例 https cr console aliyun com cn beijing instances 本地制作及发布 docker login username 阿里云用户名 registry cn beijin
  • 山坡羊·潼关怀古

    张养浩 峰峦如聚 波涛如怒 山河表里潼关路 望西都 意踌躇 伤心秦汉经行处 宫阙万间都做了土 兴 百姓苦 亡 百姓苦
  • 最简单的方法搭建属于自己的服务器。。。

    第一步 安装node环境 第二步 建立一个文件夹 新建1 js index html about html 第三步 编辑1 js 导入http模块 const http require http 导入服务器模块 const server h
  • AD20笔记-元器件绘制

    AD20笔记 文章目录 AD20笔记 新建工程 绘制元器件 绘制电阻 放置管脚 绘制效果 元器件属性设置 绘制电容 绘制管脚快捷键 元器件属性设置 添加封装属性 绘制效果 绘制电感 元器件属性设置 绘制LED灯 元器件属性设置 把线设置为细
  • 相似度计算方式汇总

    常用的下面一些距离计算方式 欧式距离 Euclidean Distance 余弦相似度 Cosine 皮尔逊相关系数 Pearson 修正余弦相似度 Adjusted Cosine 汉明距离 Hamming Distance 曼哈顿距离 M

随机推荐

  • UPC-混合训练第十五场

    gift 题目描述 战争结束 A国和B国的元首决定两国友好相处 于是城市之间就有互相送礼的情况 参与这次相互协助计划中有n个A国的城市和m个B国的城市 作为A国的重臣 小Q了解到每一个A国的城市送出了ai份礼物 B国的城市收到了bi份礼物
  • # com.alibaba.druid使用踩坑解决

    com alibaba druid使用踩坑解决 1 加入依赖
  • C语言面试malloc,c语言面试最必考的十道试题,求职必看!!!

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 6 free 函数 问 下面的程序会在用户输入 freeze 的时候出问题 而 zebra 则不会 为什么 include int main int argc char argv char pt
  • lua学习(三)关系运算符

    Lua 运算符 运算符是一个特殊的符号 用于告诉解释器执行特定的数学或逻辑运算 Lua提供了以下几种运算符类型 算术运算符 关系运算符 逻辑运算符 其他运算符 算术运算符 下表列出了 Lua 语言中的常用算术运算符 设定 A 的值为10 B
  • Android中 AIDL 实际开发步骤

    AIDL基本知识点 定义 Android 接口定义语言 作用 不同应用的客户端通过 IPC 方式访问服务 并且希望在服务中进行多线程处理时 您才有必要使用 AIDL 官方文档 Android 接口定义语言 AIDL Android 开发者
  • 【ESP32入门学习】SPI主机

    ESP32入门学习 SPI主机 ESP32有四个SPI外设 包含SPI0 SPI1 HSPI和VSPI SPI0完全专用于Flash高速缓存 ESP32用于将SPI闪存设备映射到内存中 SPI1是与SPI0连接到相同的硬件线路上 用于写入闪
  • 第十三届蓝桥杯模拟赛(第三期)试题与题解 C++

    文章目录 第十三届蓝桥杯模拟赛 第三期 试题与题解 1 试题A 题解 数制转换 2 试题B 题解 枚举 3 试题C 题解 枚举 4 试题D 题解 最小生成树 5 试题E 方法一 暴力求和 方法二 一维前缀和 方法二 二维前缀和 6 试题F
  • 一文弄清CSS三角形、梯形的本质

    核心就是border 有如下几个定理 1 border的最初表现形式为矩形 当邻边矩形存在时 两个矩形之间会用三角形补齐 2 border的高度由border width决定 border中矩形的长度由内部的宽度决定 所以说 由以上定理可知
  • vim 光标快速移动技巧总结(vim高级操作的基础)

    简单的移动适合小范围移动 利用查找适合大范围移动 利用wb以word为单位进行移动类似hjkl适合小范围移动 移动到行首行尾适合行内移动 移动到文本开头和文本结尾适合大范围移动 利用行号移动到某一行适合大范围移动 翻页适合大范围移动 利用标
  • Docker Desktop 安装和使用 (Windows)

    下载Docker Desktop 下载地址 Download Docker Desktop Docker 程序默认自动安装在C盘 如果想自定义盘符安装 需要在安装前 删除如下目录 C Program Files Docker 在D盘新建目录
  • [MATLAB] 初学入门 运用plot()函数绘制函数图像

    本文将讲述使用matlab绘制三角函数方程 参数函数方程 分段函数方程及超越函数方程图像的方法 开门见山 直接来看几道例题 A 画出方程y tan x 的图像 clc 清除命令窗口的内容 clear 清除工作空间的所有变量 clear al
  • python闯红灯检测斑马线检测红绿灯检测车速检测车流量统计车牌识别智慧交通系统

    本项目是使用pytorch作为深度学习框架的智能交通检测系统 可以识别并处理路口交通状况 目前完成的功能有 车辆 行人 摩托车 斑马线检测识别 红绿灯检测识别 车辆跟踪 车速判断 超速行为识别 交通拥堵状况识别 车流量统计 车牌检测识别 行
  • CTF(二)DES中的S盒

    如图 若输入101100 则输出0111
  • RocketMq-主从集群搭建

    目录 1 服务器列表 2 下载安装包 3 node1节点修改runserver sh文件 4 所有节点安装jdk 5 node1节点配置RocketMQ集群 1 配置node1节点borker a的master配置文件 2 配置node2节
  • SpringBoot 搭建CAS 客户端 和CAS 服务端

    第一步 搭建CAS5 3 服务端 Github 下载CAS5 3 服务端版本 https github com apereo cas overlay template tree 5 3 注意 最新的master分支使用的需要java11 该
  • C# FTP操作类

    可进行FTP的上传 下载等其他功能 支持断点续传 using System using System Collections Generic using System IO using System Linq using System Ne
  • Flutter Image 参数详解

    1 继承关系 Object gt Diagnosticablet gt DiagnosticableTreet gt Widgett gt StatefulWidgett gt Image 2 介绍 一个显示图片的widget 支持图像格式
  • Could not autowire field: private com.xxx.dao(已解决)

    最近刚在做一个关于o2o在线资源回收的一个项目 用到的框架就是SSM框架 可能有一段时间没有写代码了 一些常见的错误都折腾了半天 直接进入正题 这个图片就是当时报错的图片 当时是在控制器里注解接口的时候 运行程序直接就报错 Autowire
  • 基于springboot+vue的前后端分离后项目部署方案

    markdown body line height 1 75 font weight 400 font size 16px overflow x hidden color rgba 51 51 51 1 markdown body h1 m
  • 2023国赛数学建模思路 - 案例:感知机原理剖析及实现

    文章目录 1 感知机的直观理解 2 感知机的数学角度 3 代码实现 4 建模资料 0 赛题思路 赛题出来以后第一时间在CSDN分享 https blog csdn net dc sinor type blog 1 感知机的直观理解 感知机应