之前博客中,我有介绍到分类机器学习算法,分类的目标变量是标称型数据,本篇博客将重点对连续型的数据做出预测及回归算法。有些人会问:"回归能用来做什么?"其实回归能够做任何事情。
本文首先介绍线性回归(具体概念解释可以参考CS229,吴恩达讲义的译文:传送门),包括其名称的由来和python实现。在这之后引入了局部平滑技术,分析如何更好地你和数据。接下来,本文将探讨回归在"欠拟合"情况下的shrinkage技术,探讨偏差和方差的概念。
在具体讲解线性回归之前,咱们先来看看从宏观上分析下线性回归。
线性回归 |
|
优点 |
结果易于理解,计算上不复杂 |
缺点 |
对非线性的数据拟合的不好 |
适用数据类型 |
数值型和标称型数据 |
说到回归,一般都是指线性回归,所以本文里的回归和线性回归代表同一个意思。需要说明的是,存在另一种称为非线性回归的回归模型,该模型输入与输出的关系与线性模型并不相同。
回归的步骤:
标准回归函数的实现:
回归系数w的求解公式如下:
需要注意的是上述公式中包含,也就是需要对矩阵求逆,因此需要在代码中对的逆矩阵是否存在做出判断。
from numpy import *
def standRegres(xArr,yArr):
xMat = mat(xArr); yMat = 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)
return ws
1.2 局部加权线性回归(根据数据来局部调整预测)
线性回归的一个问题是有可能出现欠拟合现象,因为它求得是具有最小均方误差的无偏估计。所以有些方法允许在估计中引入一些偏差,从而降低预测的均方误差。其中的一个方法是局部加权线性回归(Locally Weighted Linear Regression , LWLR)。在该算法中,我们给待预测点附近的每个点赋予一定的权重,LWLR使用"核"来对附近的点赋予更高的权重。最常用的核就是高斯核,高斯核对应的权重如下:
这样就构建了一个只含对角元素的权重矩阵w,并且点x与x( i )越近,w(i,i)将会越大。上述公式包含一个需要用户指定的参数k,它决定了对附近的点赋予多大的权重,这也是使用LWLR时唯一需要考虑的参数下图显示了参数k与权重的关系。
局部加权线性回归函数的实现:
def lwlr(testPoint,xArr,yArr,k=1.0):
xMat = mat(xArr); yMat = mat(yArr).T
m = shape(xMat)[0]
weights = mat(eye((m)))
for j in range(m): #next 2 lines create weights matrix
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"
return
ws = xTx.I * (xMat.T * (weights * yMat))
return testPoint * ws
本文到此为止,介绍了提高预测精度的方法:局部加权回归,虽然局部加权回归比普通线性回归有更好的效果,但是由于每做一次预测,都必须使用整个数据集,所以会带来很大的计算量。接下来咱们介绍下另一种提高预测精度的方法,并分析它的优势所在。
1.3缩减系数来"理解"数据
如果数据的特征比样本点还多,会发现使用线性回归和之前的方法来做预测就会出错,因为如果特征比样本点还多(n>m)也就是说输入矩阵x不是满秩矩阵。非满秩矩阵在求逆时会出现问题。
为了解决这个问题,统计学家引入了岭回归(ridge regression)的概念,这就是本节将介绍的第一种缩减方法。接着是lasso法,该方法效果很好但计算复杂,本节最后介绍了第二种缩减方法,称为前向逐步回归,可以得到与lasso差不多的效果,且更容易实现。
岭回归
简单来说,岭回归就是在矩阵上加入一个lI从而使矩阵非奇异,进而能对求逆。其中矩阵I是一个m x m的单位矩阵,对角线上元素全为1,其他元素全为0。而l是一个用户定义的数值,在这种情况下,回归系数的计算公式将变成:
岭回归最先用来处理特征多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入l来限制了所有w之和,通过引入惩罚项,能够减少不重要的参数,这个技术在统计学中也叫做缩减(shrinkage)。
这里补充个小知识,大家知道岭回归的岭的由来么,岭回归使用了单位矩阵乘以常量l,我们观察其中的单位矩阵,可以看到值1贯穿整个对角线,其余元素全是0。形象地,在0构成的平面上有一条1组成的"岭",这就是岭回归中的"岭"的由来。
缩减方法可以去掉不重要的参数,因此能更好地理解数据。此外,与简单的线性回归相比,缩减法能取得更好的预测效果。
岭回归代码
def ridgeRegres(xMat,yMat,lam=0.2):
xTx = xMat.T*xMat
denom = xTx + eye(shape(xMat)[1])*lam
if linalg.det(denom) == 0.0:
print "This matrix is singular, cannot do inverse"
return
ws = denom.I * (xMat.T*yMat)
return ws
为了使用岭回归和缩减技术,首先需要对特征做标准化处理。具体做法就是所有的特征都减去各自的均值并除以方差。
还有一些其他的缩减方法,如lasso,LAR,PCA回归以及子集选择等。与岭回归一样,这些方法不敬可以提高预测精确率,而且可以解释回归系数。
Lasso
不难证明,在增加如下约束时,普通的最小二乘法回归会得到与岭回归的一样的公式:
上式限定了所有的回归系数平方和不能大于l。使用普通的最小二乘法回归在当两个或更多的特征相关时,可能会得出一个很大的正系数和很大的复习书。正是因为上述限制条件的存在,使用岭回归可以避免这个问题。
与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下:
为了在新的约束条件下解出回归系数,需要使用二次规划算法,这无疑极大地增加了计算复杂度,下面介绍一个更为简单的方法来得到结果,该方法叫做前向逐步回归。
前向逐步回归
前向逐步回归算法可以得到与lasso差不多的效果,但更简单。它属于一种贪心算法,即每一步都尽可能减少误差。一开始,所有的权重都设为1,然后每一步所做的决策是对某个权重增加或减少一个很小的值。
该算法伪代码:
具体的实现算法如下:
def stageWise(xArr,yArr,eps=0.01,numIt=100):
xMat = mat(xArr); yMat=mat(yArr).T
yMean = mean(yMat,0)
yMat = yMat - yMean #can also regularize ys but will get smaller coef
xMat = regularize(xMat)
m,n=shape(xMat)
#returnMat = zeros((numIt,n)) #testing code remove
ws = zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy()
for i in range(numIt):
print ws.T
lowestError = 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()
接下来我们来探讨下偏差与方差的概念
权衡偏差与方差
在我们使用模型时,一旦发现模型和测量值存在差异,就说出现了误差。下图我们给出了训练误差与测试误差的曲线图,上面的曲线就是测试误差,下面的曲线就是训练误差。在前面的实验我们知道当核(k取值)越小,训练误差就会变小,下图,从左到右就表示了核逐渐减小的过程。一般认为,上述两个误差由三个部分组成:偏差、测量误差和随机噪声,前面我们通过引入三个越来越小的核来不断增大模型的方差。这样我们就可以通过实际效果来看偏差和方差间的折中效果。