机器学习实战5(回归篇)

2023-11-04

目录

1、回归

2、回归代码

3、预测鲍鱼的年龄


1、回归

        前面的文章介绍了很多分类算法,分类的目标变量是标称型数据,而本文将会对连续型的数据做出预测。主要讲解简单的线性回归和局部加权线性回归,并通过预测鲍鱼年龄的实例进行实战演练。

        说到回归,一般都是指线性回归(linear regression),所以本文里的回归和线性回归代表同一个意思。线性回归意味着可以将输入项分别乘以一些常量,再将结果加起来得到输出。需要说明的是,存在另一种成为非线性回归的回归模型,该模型不认同上面的做法,比如认为输出可能是输入的乘积。

        应该怎么从一大堆数据里求出回归方程呢?假定输入数据存放在矩阵X中,结果存放在向量y中:

         而回归系数存放在向量w中:

        应当怎样从一大堆数据里求出回归方程呢?假定输人数据存放在矩阵x中,而回归系数存放在向量w中。那么对于给定的数据x,预测结果将会通过y=w^{\tau } x给出。现在的问题是,手里有一些x和对应的y,怎样才能找到w呢?一个常用的方法就是找出使误差最小的w。这里的误差是指预测y值和真实y值之间的差值,使用该误差的简单累加将使得正差值和负差值相互抵消,所以我们采用平方误差。

         用矩阵表示还可以写做:

         为啥能这么变化,记住一个前提:若x为向量,则默认x为列向量,x^T为行向量。将上述提到的数据矩阵X和标签向量y带进去,就知道为何这么变化了。在继续推导之前,我们要先明确一个目的:找到w,使平方误差和最小。因为我们认为平方误差和越小,说明线性回归拟合效果越好。现在,我们用矩阵表示的平方误差和对w进行求导:

         得到:

         令上述公式等于0,得到:

         w上方的小标记表示,这是当前可以估计出的w的最优解。从现有数据上估计出的w可能并不是数据中的真实w值,所以这里使用了一个"帽"符号来表示它仅是w的一个最佳估计。

        值得注意的是,上述公式中包含逆矩阵,也就是说,这个方程只在逆矩阵存在的时候使用,也即是这个矩阵是一个方阵,并且其行列式不为0。

        述的最佳w求解是统计学中的常见问题,除了矩阵方法外还有很多其他方法可以解决。通过调用NumPy库里的矩阵方法,我们可以仅使用几行代码就完成所需功能。该方法也称作OLS, 意思是“普通小二乘法”(ordinary least squares)。

2、回归代码

        数据集:数据在这!

        提取码:3liq

        第一列都为1.0,即x0。第二列为x1,即x轴数据。第三列为x2,即y轴数据。

标准回归函数和数据导入函数:

        第一个函数loadDataset ()加载数据。该函数打开一个用tab键分隔的文本文件,这里仍然默认文件每行的最后一个值是目标值。第二个函数standRegres()用来计算最佳拟合直线。该函数首先读人x和y并将它们保存到矩阵中;然后计算x^{\tau }x,然后判断它的行列式是否为零,如果行列式为零,那么计算逆矩阵的时候将出现错误。NumPy提供一个线性代数的库linalg,其中包含很多有用的函数。可以直接调用linalg.det()来计算行列式。最后,如果行列式非零,计算并返回w。如果没有检查行列式是否为零就试图计算矩阵的逆,将会出现错误。

#导入数据函数
def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    dataMat = []
    labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat
#标准回归函数
def standRegress(xArr,yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T*xMat
    if linalg.det(xTx) ==0.0:#矩阵为奇异矩阵,不能求逆
        print("This matrix is singular,cannot do inverse")
        return
    ws = xTx.I*(xMat.T*yMat)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue',alpha = .5)
    xCopy = xMat.copy()
    xCopy.sort(0)
    yHat = xCopy*ws #预测值
    ax.plot(xCopy[:,1],yHat)
    plt.show()
    return ws

        绘画出来的数据如图:

         输出的ws的值:

 局部加权线性回归:

        线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计。显而易见,如果模型欠拟合将不能取得最好的预测效果。所以有些方法允许在估计中引入一些偏差,从而降低预测的均方误差。

        其中的一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在该算法中,我们给待预测点附近的每个点赋予一定的权重;在这个子集上基于最小均方差来进行普通的回归。与kNN一样,这种算法每次预测均需要事先选取出对应的数据子集。该算法解出回归系数w的形式如下:

         其中W是一个矩阵,这个公式跟我们上面推导的公式的区别就在于W,它用来给每个店赋予权重。

        LWLR使用"核"(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:

         这样我们就可以根据上述公式,编写局部加权线性回归,我们通过改变k的值,可以调节回归效果,编写代码如下:

#局部加权线性回归
def lwlr(testpoint,xArr,yArr,k):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = shape(xMat)[0]
    weights = np.mat(eye((m))) #创建权重对角矩阵
    for j in range(m): #遍历数据集计算每个样本的权重
        diffMat = testpoint - xMat[j,:]
        weights[j,j] = exp(diffMat*diffMat.T/(-2*k**2))
    xTx = xMat.T*(weights*xMat)
    if linalg.det(xTx) ==0.0:
        print("this matrix is singular,cannot do inverser")
        return
    ws = xTx.I*(xMat.T*(weights*yMat))
    return testpoint*ws

def lwlrTest(testArr,xArr,yArr,k):
    m = shape(testArr)[0]
    yHat = zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)  #为每个数据集调用lwlr。这有助于求解k 的大小

    #画图
    xMat = np.mat(xArr)
    strInd = xMat[:,1].argsort(0)
    xSort = xMat[strInd][:,0,:]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(xSort[:,1],yHat[strInd])
    ax.scatter(xMat[:,1].flatten().A[0], np.mat(yArr).flatten().A[0], s = 20, c = 'red',alpha = .5)
    plt.show()
    return yHat
xArr, yArr = loadDataSet('ex0.txt')
yHat = lwlrTest(xArr,xArr,yArr,1.0) #记得修改k值

        我们可以不断修改k的值:

        当k=1.0时:

         当k=0.01时:

 当k=0.003时:

         可以看到,当k越小,拟合效果越好。但是当k过小,会出现过拟合的情况,例如k等于0.003的时候。

3、预测鲍鱼的年龄

        接下来,我们将回归用于真实数据。在data目录下有一份来自UCI数据集合的数据,记录了鲍鱼(一种介壳类水生动物)的年龄。鲍鱼年龄可以从鲍鱼壳的层数推算得到。

        可以看到,数据集是多维的,所以我们很难画出它的分布情况。每个维度数据的代表的含义没有给出,不过没有关系,我们只要知道最后一列的数据是y值就可以了,最后一列代表的是鲍鱼的真实年龄,前面几列的数据是一些鲍鱼的特征,例如鲍鱼壳的层数等。我们不做数据清理,直接用上所有特征,测试下我们的局部加权回归。

        新建abalone.py文件,添加rssError函数,用于评价最后回归结果。

def rssError(yArr,yHatArr):
    return ((yArr-yHatArr)**2).sum()
from numpy import *
import numpy as np
import matplotlib.pyplot as plt
def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    dataMat = []
    labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

def rssError(yArr,yHatArr):
    return ((yArr-yHatArr)**2).sum()

#局部加权线性回归
def lwlr(testpoint,xArr,yArr,k):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = shape(xMat)[0]
    weights = np.mat(eye((m))) #创建权重对角矩阵
    for j in range(m): #遍历数据集计算每个样本的权重
        diffMat = testpoint - xMat[j,:]
        weights[j,j] = exp(diffMat*diffMat.T/(-2*k**2))
    xTx = xMat.T*(weights*xMat)
    if linalg.det(xTx) ==0.0:
        print("this matrix is singular,cannot do inverser")
        return
    ws = xTx.I*(xMat.T*(weights*yMat))
    return testpoint*ws

def lwlrTest(testArr,xArr,yArr,k):
    m = shape(testArr)[0]
    yHat = zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)  #为每个数据集调用lwlr。这有助于求解k 的大小

    #画图
    xMat = np.mat(xArr)
    strInd = xMat[:,1].argsort(0)
    xSort = xMat[strInd][:,0,:]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(xSort[:,1],yHat[strInd])
    ax.scatter(xMat[:,1].flatten().A[0], np.mat(yArr).flatten().A[0], s = 20, c = 'red',alpha = .5)
    plt.show()
    return yHat

def standRegress(xArr,yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T*xMat
    if linalg.det(xTx) ==0.0:#矩阵为奇异矩阵,不能求逆
        print("This matrix is singular,cannot do inverse")
        return
    ws = xTx.I*(xMat.T*yMat)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue',alpha = .5)
    xCopy = xMat.copy()
    xCopy.sort(0)
    yHat = xCopy*ws #预测值
    ax.plot(xCopy[:,1],yHat)
    plt.show()
    return ws


abX, abY = loadDataSet('abalone.txt')
print('训练集与测试集相同:局部加权线性回归,核k的大小对预测的影响:')
yHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
yHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
yHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)
print('k=0.1时,误差大小为:',rssError(abY[0:99], yHat01.T))
print('k=1  时,误差大小为:',rssError(abY[0:99], yHat1.T))
print('k=10 时,误差大小为:',rssError(abY[0:99], yHat10.T))
print('')
print('训练集与测试集不同:局部加权线性回归,核k的大小是越小越好吗?更换数据集,测试结果如下:')
yHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)
yHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)
yHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)
print('k=0.1时,误差大小为:',rssError(abY[100:199], yHat01.T))
print('k=1  时,误差大小为:',rssError(abY[100:199], yHat1.T))
print('k=10 时,误差大小为:',rssError(abY[100:199], yHat10.T))
print('')
print('训练集与测试集不同:简单的线性归回与k=1时的局部加权线性回归对比:')
print('k=1时,误差大小为:', rssError(abY[100:199], yHat1.T))
ws = standRegress(abX[0:99], abY[0:99])
yHat = np.mat(abX[100:199]) * ws
print('简单的线性回归误差大小:', rssError(abY[100:199], yHat.T.A))

        输出为:

 

     可以看到,当k=0.1时,训练集误差小,但是应用于新的数据集之后,误差反而变大了。这就是经常说道的过拟合现象。我们训练的模型,我们要保证测试集准确率高,这样训练出的模型才可以应用于新的数据,也就是要加强模型的普适性。可以看到,当k=1时,局部加权线性回归和简单的线性回归得到的效果差不多。这也表明一点,必须在未知数据上比较效果才能选取到最佳模型。那么最佳的核大小是10吗?或许是,但如果想得到更好的效果,应该用10个不同的样本集做10次测试来比较结果。

        本示例展示了如何使用局部加权线性回归来构建模型,可以得到比普通线性回归更好的效果。局部加权线性回归的问题在于,每次必须在整个数据集上运行。也就是说为了做出预测,必须保存所有的训练数据。

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

机器学习实战5(回归篇) 的相关文章

随机推荐

  • 【故障诊断】基于最小熵反卷积、最大相关峰度反卷积和最大二阶环平稳盲反卷积等盲反卷积方法在机械故障诊断中的应用研究(Matlab代码实现)

    个人主页 研学社的博客 欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 2 1 稀疏最大谐波噪声比反卷积 2 2 最大相关峰度反卷积 2 3
  • 认知计算导论自救版笔记

    认知计算导论 认知数据收集 认知cognitive数据 1 定义 认知物联网IoT 认知系统和互联网组合 认知数据来源 物理世界 互联网提供大量数据 虚拟世界 社交网络和移动计算 人群感知Crowd Sensing 大量人群通过移动设备无意
  • vst开启语音服务器,VST语音遥控器体验记

    体验信息 101245hu4k1a42krae4l4s jpg 10 39 KB 下载次数 5 2015 5 30 16 34 上传物品名称 VST智能语音遥控器适配物品 101502huualwallumcbaaa jpg 3 35 KB
  • 基于数组的链表AList

    快考试了 作为数据结构的复习 那么就把代码背打一遍好了 虽然代码很简单 但是把基础打牢固对以后的学习肯定是百益而无一害 正好也练练C 模板和指针以及代码书写的模块化 否则天天写些算法程序 一写就一大坨 乱乱的 养成习惯就悲剧了 看一点写一点
  • 梅尔频率倒谱系数(MFCC)

    https blog csdn net zkl99999 article details 80723755
  • winform中如何设置splitContainer中panel的宽度,并在以后的拖动中保持不变

    搜先随便选着一个penel 按Esc键这时你会选择这个splitContainer控件 假如 你要固定penel1 这时你需要先拖动splitContainer控件 让penel1全部显示出来 然后在splitContainer控件的属性中
  • 一、Gradle入门

    文章目录 一 Gradle入门 1 1 Gradle 简介 1 2 常见的项目构建工具 1 3 Gradle 安装 1 3 1 Gradle 安装说明 1 3 2 安装 JDK 1 3 3 下载并解压到指定目录 1 3 4 配置环境变量 1
  • 关于typedef的用法总结

    typedef的应用 typedef是C 语言中用于为现有数据类型指定替代名称的关键字 它主要用于用户定义的数据类型 当数据类型的名称在程序中使用变得稍微复杂时 以下是使用的一般语法 typedef
  • Pytorch框架学习 -2 torch.nn.modules.Module(nn.Module)理解

    文章目录 Pytorch框架学习 2 torch nn modules Module nn Module 理解 最简单的例子 分析 部分源码 基本参数 dump patches version training 初始化函数 paramete
  • Vue进阶(一):v-loading实现加载效果

    原文链接 https blog csdn net sunhuaqiang1 article details 95474410 使用v loading在接口为请求到数据之前 显示加载中 直到请求到数据后消失 全局loading
  • 七牛云的使用

    1 https www qiniu com 用qq或者微信登入七牛云 2 添加一个对象存储 3 在个人中心获取appkey和appsecret 4 绑定一个域名 5 把sdk放在自己的项目中 封装一个上传的类
  • 华为笔试8.31

    Q1 int main int argc char const argv string l An introduction is the first paragraph of your paper string l a a getline
  • 【问题解决】M1芯Macbook安装python&M1 Macbook pro基本操作

    刚接触Macbook 一步一个坑 有幸家中领导赏识 才得以抚摸到传这闻已久的神器 可这神功尚未练成 差点被气的自断经脉 之前没用过苹果os系统 刚一上手各种不适应 要不是因为爱 qiong 电脑早不知道摔多少次了 F1 12哪去了 我这PK
  • 纯前端实现 导入 与 导出 Excel

    最近经常在做 不规则Excel的导入 或者一些普通Excel的导出 当前以上说的都是纯前端来实现 下面我们来聊聊经常用到的Excel导出与导入的实现方案 本文实现技术栈以 Vue2 JS 为例 导入分类 调用 API 完全由后端来解析数据
  • QT实现发送get和post请求

    介绍下如何在qt程序中给http服务端发送get和post请求 首先你要有一个http服务端 下面直接贴下代码 pro QT core gui network greaterThan QT MAJOR VERSION 4 QT widget
  • Android系统 —— 源码编译错误整理(持续更新)

    记录一些日常遇到的编译问题及解决方法 查找的时候可以直接搜索问题描述的关键部分 目录 1 更改源码目录名引发的错误 2 添加VNDK库 Vendor Native Development Kit 报错 3 头文件被重复包含 4 无法链接库文
  • 【FlashDB】第三步 FlashDB 移植 STM32L475 使用QSPI驱动外部 flash W25Q64之 FlashDB 移植

    准备事项 完成了以下两步操作后进行 FlashDB 第一步 FlashDB 移植到 STM32L475 使用QSPI驱动外部 flash W25Q64之FAL移植 FlashDB 第二步 FlashDB 移植 STM32L475 使用QSP
  • Anaconda使用教程(常用命令)

    Anaconda3安装教程 配置环境变量 图文教程 https blog csdn net love906897406 article details 125010258https blog csdn net love906897406 a
  • ECharts数据可视化

    目录 第一章 什么是ECharts 第二章 搭建环境 2 1 Echarts的下载 2 2 Visual Studio Code下载 第三章 一个简单的可视化展示 第四章 Echarts组件 4 1 标题 4 2 提示框 4 3 工具栏 4
  • 机器学习实战5(回归篇)

    目录 1 回归 2 回归代码 3 预测鲍鱼的年龄 1 回归 前面的文章介绍了很多分类算法 分类的目标变量是标称型数据 而本文将会对连续型的数据做出预测 主要讲解简单的线性回归和局部加权线性回归 并通过预测鲍鱼年龄的实例进行实战演练 说到回归