赞
踩
搜索微信公众号:‘AI-ming3526’或者’计算机视觉这件小事’ 获取更多人工智能、机器学习干货
csdn:https://blog.csdn.net/baidu_31657889/
github:https://github.com/aimi-cn/AILearners
本文出现的所有代码,均可在github上下载,不妨来个Star把谢谢~:Github代码地址
本篇文章讲解线性回归的缩减方法–岭回归以及逐步线性回归。
如果数据的特征比样本点还多应该怎么办?很显然,此时我们不能再使用上文的方法进行计算了,因为矩阵X不是满秩矩阵,非满秩矩阵在求逆时会出现问题。为了解决这个问题,统计学家引入岭回归(ridge regression)的概念。
岭回归即我们所说的L2正则线性回归,在一般的线性回归最小化均方误差的基础上增加了一个参数w的L2范数的罚项,从而最小化罚项残差平方和:
简单说来,岭回归就是在普通线性回归的基础上引入单位矩阵。回归系数的计算公式变形如下:
式中,矩阵I是一个mxm的单位矩阵,加上一个λI从而使得矩阵非奇异,进而能对矩阵求逆。
岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学中也可以叫做缩减(shrinkage)。
缩减方法可以去掉不重要的参数,因此能更好地裂解数据。此外,与简单的线性回归相比,缩减法能够取得更好的预测效果。
为了使用岭回归和缩减技术,首先需要对特征做标准化处理。因为,我们需要使每个维度特征具有相同的重要性。本文使用的标准化处理比较简单,就是将所有特征都减去各自的均值并除以方差。
创建regression02.py文件
代码很简单,处理的文件是前文中的鲍鱼的数据,只需要稍做修改,其中,λ为模型的参数。我们先绘制一个回归系数与log(λ)的曲线图,看下它们的规律,编写代码如下:
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @File : regression.py @Time : 2019/07/01 19:02:32 @Author : xiao ming @Version : 1.0 @Contact : xiaoming3526@gmail.com @Desc : 岭回归以及逐步线性回归 @github : https://github.com/aimi-cn/AILearners ''' # here put the import lib import numpy as np import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties ''' @description: 加载数据 @param:fileName - 文件名 @return: xArr - x数据集 yArr - y数据集 ''' def loadDataSet(fileName): numFeat = len(open(fileName).readline().split('\t')) - 1 xArr = []; yArr = [] fr = open(fileName) for line in fr.readlines(): lineArr =[] curLine = line.strip().split('\t') for i in range(numFeat): lineArr.append(float(curLine[i])) xArr.append(lineArr) yArr.append(float(curLine[-1])) return xArr, yArr ''' @description: 岭回归 @param: xMat - x数据集 yMat - y数据集 lam - 缩减系数 @return: ws - 回归系数 ''' def ridgeRegres(xMat, yMat, lam = 0.2): xTx = xMat.T * xMat denom = xTx + np.eye(np.shape(xMat)[1]) * lam if np.linalg.det(denom) == 0.0: print("矩阵为奇异矩阵,不能转置") return ws = denom.I * (xMat.T * yMat) return ws ''' @description: 岭回归测试 @param:xMat - x数据集 yMat - y数据集 @return: wMat - 回归系数矩阵 ''' def ridgeTest(xArr, yArr): xMat = np.mat(xArr); yMat = np.mat(yArr).T #数据标准化 yMean = np.mean(yMat, axis = 0) #行与行操作,求均值 yMat = yMat - yMean #数据减去均值 xMeans = np.mean(xMat, axis = 0) #行与行操作,求均值 xVar = np.var(xMat, axis = 0) #行与行操作,求方差 xMat = (xMat - xMeans) / xVar #数据减去均值除以方差实现标准化 numTestPts = 30 #30个不同的lambda测试 wMat = np.zeros((numTestPts, np.shape(xMat)[1])) #初始回归系数矩阵 for i in range(numTestPts): #改变lambda计算回归系数 ws = ridgeRegres(xMat, yMat, np.exp(i - 10)) #lambda以e的指数变化,最初是一个非常小的数, wMat[i, :] = ws.T #计算回归系数矩阵 return wMat ''' @description: 绘制岭回归系数矩阵 @param:None @return: None ''' def plotwMat(): font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) abX, abY = loadDataSet('C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/abalone.txt') redgeWeights = ridgeTest(abX, abY) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(redgeWeights) ax_title_text = ax.set_title(u'log(lambada)与回归系数的关系', FontProperties = font) ax_xlabel_text = ax.set_xlabel(u'log(lambada)', FontProperties = font) ax_ylabel_text = ax.set_ylabel(u'回归系数', FontProperties = font) plt.setp(ax_title_text, size = 20, weight = 'bold', color = 'red') plt.setp(ax_xlabel_text, size = 10, weight = 'bold', color = 'black') plt.setp(ax_ylabel_text, size = 10, weight = 'bold', color = 'black') plt.show() if __name__ == '__main__': plotwMat()
运行结果如下:
图绘制了回归系数与log(λ)的关系。在最左边,即λ最小时,可以得到所有系数的原始值(与线性回归一致);而在右边,系数全部缩减成0;在中间部分的某个位置,将会得到最好的预测结果。想要得到最佳的λ参数,可以使用交叉验证的方式获得,文章的后面会继续讲解。
前向逐步线性回归算法属于一种贪心算法,即每一步都尽可能减少误差。我们计算回归系数,不再是通过公式计算,而是通过每次微调各个回归系数,然后计算预测误差。那个使误差最小的一组回归系数,就是我们需要的最佳回归系数。
创建regression03.py文件
前向逐步线性回归实现也很简单。当然,还是先进行数据标准化,编写代码如下:
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @File : regression03.py @Time : 2019/07/15 20:47:44 @Author : xiao ming @Version : 1.0 @Contact : xiaoming3526@gmail.com @Desc : 岭回归以及逐步线性回归 @github : https://github.com/aimi-cn/AILearners ''' # here put the import lib from matplotlib.font_manager import FontProperties import matplotlib.pyplot as plt import numpy as np ''' @description: 加载数据 @param: fileName - 文件名 @return: xArr - x数据集 yArr - y数据集 ''' def loadDataSet(fileName): numFeat = len(open(fileName).readline().split('\t')) - 1 xArr = []; yArr = [] fr = open(fileName) for line in fr.readlines(): lineArr =[] curLine = line.strip().split('\t') for i in range(numFeat): lineArr.append(float(curLine[i])) xArr.append(lineArr) yArr.append(float(curLine[-1])) return xArr, yArr ''' @description: 数据标准化 @param: xMat - x数据集 yMat - y数据集 @return: inxMat - 标准化后的x数据集 inyMat - 标准化后的y数据集 ''' def regularize(xMat, yMat): inxMat = xMat.copy() #数据拷贝 inyMat = yMat.copy() yMean = np.mean(yMat, 0) #行与行操作,求均值 inyMat = yMat - yMean #数据减去均值 inMeans = np.mean(inxMat, 0) #行与行操作,求均值 inVar = np.var(inxMat, 0) #行与行操作,求方差 inxMat = (inxMat - inMeans) / inVar #数据减去均值除以方差实现标准化 return inxMat, inyMat ''' @description: 计算平方误差 @param:yArr - 预测值 yHatArr - 真实值 @return: 平方误差 ''' def rssError(yArr,yHatArr): return ((yArr-yHatArr)**2).sum() ''' @description: 前向逐步线性回归 @param: xArr - x输入数据 yArr - y预测数据 eps - 每次迭代需要调整的步长 numIt - 迭代次数 @return: returnMat - numIt次迭代的回归系数矩阵 ''' def stageWise(xArr, yArr, eps = 0.01, numIt = 100): xMat = np.mat(xArr); yMat = np.mat(yArr).T #数据集 xMat, yMat = regularize(xMat, yMat) #数据标准化 m, n = np.shape(xMat) returnMat = np.zeros((numIt, n)) #初始化numIt次迭代的回归系数矩阵 ws = np.zeros((n, 1)) #初始化回归系数矩阵 wsTest = ws.copy() wsMax = ws.copy() for i in range(numIt): #迭代numIt次 # print(ws.T) #打印当前回归系数矩阵 lowestError = float('inf'); #正无穷 for j in range(n): #遍历每个特征的回归系数 for sign in [-1, 1]: wsTest = ws.copy() wsTest[j] += eps * sign #微调回归系数 yTest = xMat * wsTest #计算预测值 rssE = rssError(yMat.A, yTest.A) #计算平方误差 if rssE < lowestError: #如果误差更小,则更新当前的最佳回归系数 lowestError = rssE wsMax = wsTest ws = wsMax.copy() returnMat[i,:] = ws.T #记录numIt次迭代的回归系数矩阵 return returnMat ''' @description: 绘制岭回归系数矩阵 @param:None @return: None ''' def plotstageWiseMat(): font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) xArr, yArr = loadDataSet('C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/abalone.txt') returnMat = stageWise(xArr, yArr, 0.005, 1000) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(returnMat) ax_title_text = ax.set_title(u'前向逐步回归:迭代次数与回归系数的关系', FontProperties = font) ax_xlabel_text = ax.set_xlabel(u'迭代次数', FontProperties = font) ax_ylabel_text = ax.set_ylabel(u'回归系数', FontProperties = font) plt.setp(ax_title_text, size = 15, weight = 'bold', color = 'red') plt.setp(ax_xlabel_text, size = 10, weight = 'bold', color = 'black') plt.setp(ax_ylabel_text, size = 10, weight = 'bold', color = 'black') plt.show() if __name__ == '__main__': plotstageWiseMat()
运行结果如下:
还是,我们打印了迭代次数与回归系数的关系曲线。可以看到,有些系数从始至终都是约为0的,这说明它们不对目标造成任何影响,也就是说这些特征很可能是不需要的。逐步线性回归算法的优点在于它可以帮助人们理解有的模型并做出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。
总结一下:
缩减方法(逐步线性回归或岭回归),就是将一些系数缩减成很小的值或者直接缩减为0。这样做,就增大了模型的偏差(减少了一些特征的权重),通过把一些特征的回归系数缩减到0,同时也就减少了模型的复杂度。消除了多余的特征之后,模型更容易理解,同时也降低了预测误差。但是当缩减过于严厉的时候,就会出现过拟合的现象,即用训练集预测结果很好,用测试集预测就糟糕很多。
AIMI-CN AI学习交流群【1015286623】 获取更多AI资料
扫码加群:
分享技术,乐享生活:我们的公众号‘计算机视觉这件小事’每周推送“AI”系列资讯类文章,欢迎您的关注!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。