回归分析中最常用的最小二乘法是一种无偏估计, 回归系数矩阵为
当X不是列满秩矩阵时,即特征数n比样本数m还多,则X.T*X的行列式为0,逆不存在。或者X的某些列的线性相关比较大时,则X.T*X的行列式接近0,X.T*X为病态矩阵(接近于奇异),此时计算其逆矩阵误差会很大,传统的最小二乘法缺乏稳定性与可靠性。
为了解决这个问题,统计学家引入岭回归的概念。简单来说,岭回归就是在矩阵X.T*X上加上一个λI从而使矩阵非奇异,进而能对 X.T*X + λI 求逆。其中,λ是一个用户给定的参数,I是一个nxn的单位矩阵(像是在0构成的平面上有条1组成的“岭”)。
在这种情况下,回归系数的计算公式为:
本篇的样例使用数据集如下(只显示了很小一部分),它使用8个特征预测一种海洋动物的年龄,部分特征间线性相关度比较高。样本总数为4177。
对于本数据集,回归系数矩阵中各项回归系数随λ的变化规律如下:
图左边λ很小,接近0时,回归系数与最小二乘法一致;图右边,λ非常大时,各项回归系数向0靠近;λ取在中间部分的某值将可以取得较好的预测效果。
示例代码如下:
from numpy import *
def loadDataSet(fileName): #general function to parse tab -delimited floats
numFeat = len(open(fileName).readline().split('\t')) - 1 #get number of fields
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): #yArr and yHatArr both need to be arrays
return ((yArr-yHatArr)**2).sum()
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
def ridgeTest(xArr,yArr):
xMat = mat(xArr)
yMat=mat(yArr).T
#数据标准化(归一化)
yMean = mean(yMat,axis =0)
yMat = yMat - yMean #to eliminate X0 take mean off of Y
print(yMat.shape)
#regularize X's
xMat = regularize(xMat)
numTestPts = 30 ###
wMat = zeros((numTestPts,shape(xMat)[1]))
for i in range(numTestPts): # 测试不同的lambda时求得的系数矩阵
ws = ridgeRegres(xMat,yMat,exp(i-10)) #让 labmda 指数变化,广覆盖
#Y_predict = xMat*ws +yMean
wMat[i,:]=ws.T #保存不同的lambda时求得各个系数矩阵
return wMat
def regularize(xMat):#regularize by columns
inMat = xMat.copy()
inMeans = mean(inMat,axis=0) #calc mean then subtract it off
inVar = var(inMat,0) #calc variance of Xi then divide by it
inMat = (inMat - inMeans)/inVar #减去均值,再除以标准差
return inMat
X,Y = loadDataSet("abalone.txt")
ridgeWeights = ridgeTest(X,Y)
print(ridgeWeights.shape)
import matplotlib.pyplot as plt
n = ridgeWeights.shape[1]#特征数
numTestPts = 30 ###
for i in range(n):
plt.plot(arange(numTestPts)-10, ridgeWeights[:,i], label = "W(%s)"%i)
plt.legend(loc="upper right")
#$\lambda\ $ 注意这里的空格符
plt.title(r"岭回归 回归系数随$\lambda\ $变化规律""\n基于数据集'abalone.txt'", fontsize=16)
plt.xlabel(r"ln($\lambda\ $)")
plt.grid(ls="--",lw =1)
plt.show()
xMat_normilized = regularize(mat(X))
rssErrorList=[]
for i in range(numTestPts):
Y_predict = xMat_normilized*ridgeWeights[i].reshape(n,1) +mean(mat(Y).T,axis =0)
RSS = rssError(array(Y).T, array(Y_predict))
rssErrorList.append(RSS)
plt.plot(arange(numTestPts)-10, rssErrorList)
plt.xlabel(r"ln($\lambda\ $)")
plt.ylabel(r"RSS")
plt.show()
for i in range(20,25):
Y_predict = xMat_normilized*ridgeWeights[i].reshape(n,1) +mean(mat(Y).T,axis =0)
RSS = rssError(array(Y).T, array(Y_predict))
#rssErrorList.append(RSS)
plt.plot(array(Y)[1000:1100],label= "Y_True(train set)")
plt.plot(Y_predict[1000:1100], label="Y_Predict")
plt.title("ln("r"$\lambda\ $"")=%d, RSS =%.1f "%(i-10, RSS))
plt.legend()
plt.show()
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!