回归的目的是预测数值型的目标值。即找到一个回归方程,通过求解其中的回归系数(该过程就称为回归),给定输入来得到预测值。这里我们之谈论线性回归。
用线性回归找最佳拟合直线
回归的一般方法:
- 收集数据;
- 准备数据;
- 分析数据:可以绘出数据的可视化二维图将有助于对数据做出理解和分析,在采用缩减法求得新回归系数之后,可以将新拟合线绘在图上作为对比
- 训练算法:找到回归系数
- 测试算法:使用R^2或者预测值和数据的拟合度,来分析模型的效果
- 使用算法;
from numpy import*
"""数据导入函数"""
def loadDataSet(fileName):
numFeat=len(open(fileName).readline().split('\t'))-1 #特征数包括了x0
dataMat=[] #数据矩阵(其实是包括了x0的X矩阵)
labelMat=[] #标签矩阵
fr=open(fileName)
for line in fr.readlines():
lineArr=[]
curLine=line.strip().split('\t') #每一行是一个样本的数据x0,x1,y.注意x0恒为1,实际上是人为加在b前面的,用于方便矩阵运算
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr) #每一个样本的x0~xn加入矩阵X
labelMat.append(float(curLine[-1])) #每个样本的标签加入向量Y
return dataMat,labelMat #返回X,Y
"""标准线性回归函数"""
def standRegres(xArr,yArr):
xMat=mat(xArr)
yMat=mat(yArr).T
xTx=xMat.T*xMat #计算 X^T*X
if (linalg.det(xTx)==0.0): #linalg模块包含线性代数的函数 det用于计算矩阵的行列式
print("该矩阵是奇异的,没有逆矩阵")
return
ws=xTx.I*(xMat.T*yMat) #计算w=(X^T*X)^-1*X^Ty
return ws
局部加权线性回归
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方差的无偏估计。所有有些方法允许在估计中引入一些偏差,从而降低预测的均方误差。局部加权线性回归就是其中的一个方法。该算法中,我们给待预测点附近的每个点赋予一定的权重,然后在这个子集上基于最小均方差来进行普通的回归。这种算法每次预测均需要事先选取出对应的数据子集。
该算法解出的回归系数w形式如下:
w=(X^T*W*X)^-1*X^TWy
其中W是矩阵,用来给每个数据点赋予权重。
局部加权线性回归使用“核”来对附近的点赋予更高的权重,一般的是使用高斯核。高斯核对应的权重如下:
w(i,i)=exp(|x(i)-x|/-2k^2)
这样就构建了一个只含对角元素的权重矩阵W,并且点x与x(i)越近,w(i,i)将会越大。k由用户指定,它决定了对附近的点赋予多大的权重。
def lwlr(testPoint,xArr,yArr,k=1.0): #testPoint为待预测点
xMat=mat(xArr)
yMat=mat(yArr).T
m=shape(xMat)[0]
weights=mat(eye((m))) #创建对角阵
for j in range(m):
diffMat=testPoint-xMat[j,:]
weights[j,j]=exp(diffMat*diffMat.T/(-2.0*k**2)) #随着样本点与待预测点距离的递增,权重将以指数级衰减,k用于控制衰减速度
xTx=xMat.T*(weights*xMat)
if linalg.det(xTx)==0.0:
print("该矩阵是奇异矩阵,没有逆矩阵")
return
ws=xTx.I*(xMat.T*(weights*yMat)) #计算系数
return testPoint*ws #返回预测值
缩减系数来“理解”数据
如果数据的特征比样本点还多(n>m),也就是说输入数据的矩阵X不是满秩矩阵,那么X是不能求逆矩阵的。为了解决这个问题,引入领回归和向前逐步回归。
岭回归
简单的说岭回归就是在矩阵X^T*X上加一个λE,使得矩阵可逆。E是m*m的单位阵。这种情况下,回归系数的计算公式变成:
w=(X^T*X+λE)^-1*X^T*y
岭回归最先用于处理特征数多余样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能够减少不重要的参数,统计上称为缩减。
"""岭回归"""
def ridgeRegres(xMat,yMat,lam=0.2):
xTx=xMat.T*xMat
denom=xTx+eye(shape(xMat)[1])*lam #X^T*X+λE
if linalg.det(denom)==0.0:
print("该矩阵是奇异矩阵,没有逆矩阵")
return
ws=denom.I*(xMat.T*yMat)
return ws #返回w
前向逐步回归
属于一种贪心算法,即每一步都尽可能减少误差。一开始,所有的权重都设为1,然后每一步所做的决策是对某个权重增加或者减少一个很小的值。
伪代码如下:
数据标准化,使其分布满足0均值和单位方差
在每轮迭代过程中:
设置当前最小误差lowestError为正无穷
对每个特征:
增大或者缩小:
改变一个系数得到一个新的W
计算新W下的误差
如果误差Error小于当前最小误差lowestError:
设置Wbest等于当前的W
将W设置为新的Wbest
"""前向逐步线性回归"""
def stageWise(xArr,yArr,eps=0.01,numIt=100): #eps表示每次迭代需要调整的步长,numIt表示迭代次数
xMat=mat(xArr)
yMat=mat(yArr).T
yMean=mean(yMat,0) #mean()求取均值:0压缩行,对各列求均值,返回 1* n 矩阵;1缩列,对各行求均值,返回 m *1 矩阵
yMat=yMat-yMean #0均值,即每个数据减去均值
xMat=regularize(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.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()
returnMat[i,:]=ws.T