《机器学习实战》笔记之八——预测数值型数据:回归

2024-05-15 05:48

本文主要是介绍《机器学习实战》笔记之八——预测数值型数据:回归,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第八章 预测数值型数据:回归


8.1 用线性回归找到最佳拟合曲线

假设输入数据存放在矩阵X中,而回归系数存放在向量w中,那么对于给定的数据X1,预测结果将会通过Y1=X1.T×w给出。如何找出误差最小的W,一般采用平方误差最小,即最小二乘法。平方误差可以写做:

用矩阵表示还可以写做(y-x*w).T*(y-x*w)。如果对w求导,得到x.T*(y-xw),令其等于零,得到:

w帽即为当前估计出的w的最优值,表示最佳估计。一般数据矩阵x并非有逆,而公式中需要对x.T*x求逆,一般指伪逆,python的numpy包中,linalg函数有函数pinv求伪逆,也即x.T*x的逆。

拟合数据:

#!/usr/bin/env python
# coding=utf-8from numpy import *
from sklearn import linear_modeldef loadDataSet(fileName):numFeat  = len(open(fileName).readline().split("\t"))-1#-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, labelMatdef standRegres(xArr, yArr):xMat = mat(xArr)yMat = mat(yArr).T#原始文件为m*n的矩阵,那么特征矩阵dataMat为m*(n-1)维,labelMat为m*1维,xTx  = xMat.T*xMatif linalg.det(xTx) == 0.0:                      #计算行列式是否为0print "this matrix is singular, cannot do inverse"ws = linalg.pinv(xTx)*(xMat.T*yMat)       #用伪逆来代替逆return wsws = xTx.I*(xMat.T*yMat)return wsxArr, yArr = loadDataSet("ex0.txt")
ws   = standRegres(xArr, yArr)#回归系数
print "最小二乘法得到的回归系数:\n",wsxMat = mat(xArr)
yMat = mat(yArr)
yHat = xMat*ws          #预测值#===============绘制数据集散点图和最佳拟合直线图=======
import matplotlib.pyplot as plt
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:,0].flatten().A[0])
xCopy = xMat.copy()
yHat  = xCopy*ws
ax.plot(xCopy[:,1], yHat)
plt.show()#====================皮尔逊相关系数计算两个向量的相关性===
yHat = xMat*ws
print "皮尔逊相关系数计算预测值和真实值之间的相关性:\n",corrcoef(yHat.T, yMat)
#================sklearn里面的线性回归================clf = linear_model.LinearRegression(fit_intercept=False)
clf.fit(xArr,yArr)
print "sklearn 里面线性回归训练得到的回归系数:\n",clf.coef_
得到的系数即预测值与真实值之间的相关性:

Figure 8-1: 预测得到的回归系数
可以看出sklearn里面预测的和计算的回归系数是一样的。
Figure 8-2: 拟合曲线及原始数据的散点图

python sklearn包中有计算线性回归的机器学习算法:

Figure 8-3: sklearn 计算线性回归方程

8.2 局部加权线性回归

局部加权线性回归(Locally Weighted Linear Regression, LWLR)

给待预测点附近的每个点赋予一定的权重,然后在这个子集上基于最小均方差来进行普通的回归。算法预测每次均需要事先取出对应的数据子集,解出的回归系数w的形式如下:

其中W是一个矩阵,用来给每个数据点赋予权重。

LWLR使用“核”来对附近的点赋予更高的权重,该加权模型认为样本点距离越近,越可能符合同一个线性模型。核的类型通常用高斯核。权重计算如下:

权重矩阵w为对角阵,点x与x(i)越近,w(i,i)将会越大。

coding:

#===============局部加权线性回归函数==================
def lwlr(testPoint, xArr, yArr, k=1.0):xMat    = mat(xArr)yMat    = mat(yArr).Tm       = shape(xMat)[0]    #xMat的行数weights = mat(eye((m)))     #创建对角阵for j in range(m):          #对每个点的计算都用上了整个数据集diffMat = testPoint - xMat[j,:]weights[j, j] = exp(diffMat*diffMat.T/(-2.0*k**2))#高斯核,对角阵,随样本点与待预测点距离的递增,权重值大小以指数级衰减xTx = xMat.T *(weights*xMat)if linalg.det(xTx)==0.0:print "this matrix is singular, cannot do inverse"ws = linalg.pinv(xTx)*(xMat.T*(weights*yMat))ws =xTx.I*(xMat.T*(weights*yMat))                   #回归参数return testPoint*wsdef lwlrTest(testArr, xArr, yArr, k=1.0): #当对testArr中所有点的估计,testArr=xArr时,即对所以点的全部估计m = shape(testArr)[0]yHat = zeros(m)for i in range(m):yHat[i] = lwlr(testArr[i], xArr, yArr, k)return yHatxArr, yArr = loadDataSet("ex0.txt")
print "原始值:",yArr[0]
print "估计值,k为1.0:",lwlr(xArr[0], xArr, yArr,1.0)
print "估计值:k为0.001",lwlr(xArr[0], xArr, yArr,0.001)
#=========对所有点进行估计,绘图========
yHat = lwlrTest(xArr, xArr, yArr, 0.003)
xMat = mat(xArr)
srtInd = xMat[:,1].argsort(0)
xSort  = xMat[srtInd][:,0,:]fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot(xSort[:,1], yHat[srtInd])
ax.scatter(xMat[:,1].flatten().A[0], mat(yArr).T.flatten().A[0], s = 2, c = "red")
plt.show()

 效果:

Figure 8-5: LWLR对第一个点的估计




Figure 8-6: k分别为1.0, 0.01, 0.003时的模拟效果,上图欠拟合,下图则过拟合

缺点:LWLR增加了计算量,对每个点做预测时都必需使用整个数据集。在Figure 8-4图中,k=0.01时,对预测点x=0.5估计的时候,大多数据点的权重为0, 就不必用上整个数据集,避免增加计算量。


8.3 示例:预测鲍鱼的年龄

使用真实的数据观察k值对模型的效果,数据来自UCI数据集,预测鲍鱼的年龄。


Figure 8-7: 鲍鱼数据

#============预测鲍鱼的年龄================
def rssError(yArr, yHatArr):return ((yArr - yHatArr)**2).sum()#========训练集上的误差
abX, abY = loadDataSet("abalone.txt")
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)
#========测试集上的误差
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)ws = standRegres(abX[0:99], abY[0:99])
yHat = mat(abX[100:199])*ws
print "简单线性回归上的误差和:",rssError(abY[100:199],yHat.T.A)

使用较小的核得到较低的训练误差,但会导致过拟合,也即对新的数据预测的效果比较糟糕。在简单线性回归中,达到了与局部加权线性回归类似的效果,在未知数据中,比较效果才能选取到最佳模型。


8.4  缩减系数来“理解”数据

当数据的特征比样本点还多时,就不能再用线性回归和LWLR,因为计算x.T*x的逆时会出错。为此引入岭回归(ridge regression)的概念。

岭回归

岭回归即在矩阵x.T*x上加一个λI从而使得矩阵非奇异,进而能对x.T*x+λI求逆,此时回归系数的计算公式变为:

岭回归最先用来处理特征数多于样本数的情况,在估计中加入偏差,从而得到更好的估计。引入λ来限制了所有w之和,通过引入该乘法项,能够减少不重要的参数,即缩减(shrinkage)技术。

缩减能够去掉不重要的参数,因此能够更好的理解数据,取得更好的预测效果。

使用岭回归和缩减技术,需要对特征做标准化处理,即所有特征都减去各自的均值并除以方差。

#=========岭回归==========
def ridgeRegres(xMat, yMat, lam=0.2):xTx   = xMat.T*xMatdenom = xTx + eye(shape(xMat)[1])*lam #得到中间结果,eye(shape(xMat)[1])得到xMat列数的单位对称阵if linalg.det(denom) ==0.0:print "this matrix is singular, cannot do inverse"ws = linalg.pinv(denom)*(xMat.T*yMat)ws = denom.I*(xMat.T*yMat)return wsdef ridgeTest(xArr, yArr):xMat       = mat(xArr)yMat       = mat(yArr).TyMean      = mean(yMat,0)            #按照行取平均,每行平均yMat       = yMat - yMean            #对y进行标准化xMeans     = mean(xMat, 0)xVar       = var(xMat, 0)            #按行取方差xMat       = (xMat - xMeans)/xVar    #对数据进行标准化numTestPts = 30wMat       = zeros((numTestPts, shape(xMat)[1]))for i in range(numTestPts):                 #进行numTestPts次计算岭回归,每次的系数向量都放到wMat的一行中。ws = ridgeRegres(xMat, yMat, exp(i-10)) #参数lam每次以exp(i-10)变化wMat[i,:] = ws.Treturn wMatabX, abY     = loadDataSet("abalone.txt")
ridgeWeights = ridgeTest(abX, abY)
fig = plt.figure()   
ax  = fig.add_subplot(111)
ax.plot(ridgeWeights)       #ridgeWeights,为30*8的矩阵,对矩阵画图,则以每列为一个根线,为纵坐标,横坐标为range(shape(ridgeWeights)[0])也即从0到29,第一行的横坐标为0,最后一行的行坐标为29
plt.show()


Figure 8-8: 岭回归参数与回归系数的关系

上图显示回归系数与log(λ)的关系,最左边λ最小时,8个系数的原始值与线性回归一样,最右边8个回归系数全部缩减为0,为找到最佳参数λ,还需要将ws乘以测试集比较原始测试集对比误差大小。0对应lam=exp(0-10),30对应lam=exp(30-10)

lasso

在增加约束:所有回归系数的平方和不能大于λ的条件下。普通的最小二乘法回归会得到与岭回归一样的公式。


使用普通的最小二乘法回归在两个或更多的特征相关时,可能会得出一个很大的正系数和一个很大的负系数。在上述约束中,可以约束避免这个问题。

缩减方法lasso也对回归系数做了约束:


λ足够小的时候,一些系数会被迫缩减到0。约束条件为平方差的时候,可通过求偏导找到最优解,为绝对值形式时,需要使用二次规划,这里使用前向逐步回归。

前向逐步回归

每一步都尽可能减少误差,每一步所做的决策是对某个权重增加或减少一个很小的值。

伪代码:


coding:

#=============前向逐步回归=================
def regularize(xMat):           #按行标准化inMat = xMat.copy()inMeans = mean(inMat, 0)inVar   = var(inMat, 0)inMat   = (inMat-inMeans)/inVarreturn inMatdef stageWise(xArr, yArr, eps=0.01, numIt=100):xMat      = mat(xArr)yMat      = mat(yArr).TyMean     = mean(yMat, 0)yMat      = yMat - yMeanxMat      = regularize(xMat)        #对xMat进行标准化m,n       = shape(xMat)returnMat = zeros((numIt, n))ws        = zeros((n,1))wsTest    = ws.copy()wsMax     = ws.copy()for i in range(numIt):#print ws.TlowestError = inffor j in range(n):for sign in [-1,1]:         #分别计算增加或减少该特征对误差的影响wsTest     = ws.copy()wsTest[j] += eps*signyTest      = xMat*wsTestrssE       = rssError(yMat.A, yTest.A)#得到平方误差进行比较if rssE < lowestError:lowestError = rssEwsMax       = wsTestws = wsMax.copy()returnMat[i,:] = ws.Treturn returnMatxArr,yArr = loadDataSet("abalone.txt")
print "步长为0.01,迭代次数为200:\n",stageWise(xArr, yArr, 0.01, 200)
print "步长为0.001,迭代次数为5000:\n",stageWise(xArr, yArr, 0.001, 5000)xMat = mat(xArr)
yMat = mat(yArr).T
xMat = regularize(xMat)
yM   = mean(yMat, 0)
yMat = yMat- yM
weights = standRegres(xMat, yMat.T)
print weights.T


Figure 8-9: 逐步线性回归迭代得到的回归系数


逐步线性回归算法可以帮助人们理解现有的模型并做出改进。构建了一个模型后,可以运行算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。如上面步长0.01,迭代200次后为w1和w6都为0,表明它们对目标值没有影响,也即这些特征很可能是不需要的。
当应用缩减方法(逐步线性回归或岭回归)时,模型也就增加了偏差(bias),与此同时却减少了模型的方差。

8.5 权衡偏差与方差

方差:模型训练时,模型值之间的差异。

偏差:模型预测值与数据之间的差异。

通过缩减法,可以将一些系数缩减成很小的值或者为0,增大模型偏差,同时模型复杂度降低 。

8.6 示例:预测乐高玩具套装的价格

步骤:

  1. 收集数据:用Google Shopping的API收集数据。
  2. 准备数据:从返回的JSON数据中抽取价格。
  3. 分析数据:可视化并观察数据。
  4. 训练算法:构建不同的模型,采用逐步线性回归和直接的线性回归模型。
  5. 测试算法:使用交叉验证来测试不同的模型,分析哪个效果最好。
  6. 使用算法:生成数据模型。
收集数据:使用Google购物的API

待续。。。


8.7 小结 

数据集上计算出的回归方程并不一定意味着它是最佳的,可以使用预测值yHat和原始值y的相关性来度量回归方程的好坏。

当数据的样本数比特征数还少时候,矩阵x.T*x的逆不能直接计算。即便当样本数比特征数多时,x.T*x的逆仍有可能无法直接计算,这是因为特征有可能高度相关。这时可以考虑使用岭回归,因为当x.T*x的逆不能计算时,它仍保证能求得回归参数。
岭回归是缩减法的一种,相当于对回归系数的大小施加了限制。 另一种很好的缩减法是lasso。Lasso难以求解,但可以使用计算简便的逐步线性回归方法来求得近似结果。
缩减法还可以看做是对一个模型增加偏差的同时减少方差。偏差方差折中是一个重要的概念,可以帮助我们理解现有模型并做出改进,从而得到更好的模型。


这篇关于《机器学习实战》笔记之八——预测数值型数据:回归的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990973

相关文章

批量导入txt数据到的redis过程

《批量导入txt数据到的redis过程》用户通过将Redis命令逐行写入txt文件,利用管道模式运行客户端,成功执行批量删除以Product*匹配的Key操作,提高了数据清理效率... 目录批量导入txt数据到Redisjs把redis命令按一条 一行写到txt中管道命令运行redis客户端成功了批量删除k

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例

《PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例》词嵌入解决NLP维度灾难,捕捉语义关系,PyTorch的nn.Embedding模块提供灵活实现,支持参数配置、预训练及变长... 目录一、词嵌入(Word Embedding)简介为什么需要词嵌入?二、PyTorch中的nn.Em

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1