标准回归函数和数据导入函数:
import numpy as np
#打开一个用tab键分割的文本文件
def loadDataSet(fileName):
numFeat = len(open(fileName).readline().split('\t')) - 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,labelMat
#计算最佳拟合直线
def standRegres(xArr, yArr):
xMat = np.mat(xArr); yMat = np.mat(yArr).T
xTx = xMat.T*xMat #计算x^Tx
#判断行列式是否为0
if np.linalg.det(xTx) == 0.0:
print("This matrix is singular, cannot do inverse") #计算逆矩阵出现错误
return
ws = xTx.I * (xMat.T*yMat) #I是逆矩阵
return ws
def plotDataSet():
xArr, yArr = loadDataSet('ex0.txt') #加载数据集
n = len(xArr) #数据个数
xcord = []; ycord = [] #样本点
for i in range(n):
xcord.append(xArr[i][1]); ycord.append(yArr[i]) #样本点
fig = plt.figure()
ax = fig.add_subplot(111) #添加subplot
ax.scatter(xcord, ycord, s = 20, c = 'blue',alpha = .5) #绘制样本点
plt.title('DataSet') #绘制title
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
if __name__ == '__main__':
plotDataSet()
线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计。
局部加权线性回归:给待预测点附近的每个点赋予一定的权重,在这个子集上基于最小均方差来进行普通的回归,与kNN一样,这种算法每次预测均需要事先选取对应的数据子集,该算法解出回归系数w的形式如下: w = (XTWX) -1 XT Wy 其中w是一个矩阵,用来给每个数据点赋予权重
LWLR使用核来对附近的点赋予更高的权重
最常用的是高斯核,对应的权重w(i,j)=exp(|x(i)-x|/-2k2)
def lwlr(testPoint, xArr, yArr, k=1.0):
xMat = np.mat(xArr);yMat = np.mat(yArr).T
m = np.shape(xMat)[0]
weights = np.mat(np.eye((m))) #创建对角矩阵
for j in range(m):
diffMat = testPoint - xMat[j,:]
weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2)) #权重值大小以指数级衰减
xTx = xMat.T * (weights * xMat)
if np.linalg.det(xTx) == 0.0:
print("This matrix is singular,cannot do inverse")
return
ws = xTx.I * (xMat.T * (weights * yMat))
return testPoint * ws
def lwlrTest(testArr, xArr, yArr, k=1.0):
m = np.shape(testArr)[0]
yHat = np.zeros(m)
for i in range(m):
yHat[i] = lwlr(testArr[i],xArr,yArr,k)
return yHat
如果数据的特征比样本点还多,也就是说输入数据的矩阵x不是满秩矩阵,非满秩矩阵在求逆在求逆时会出现问题。
岭回归:就是在矩阵xTX上加上一个λI从而使得矩阵非奇异,进而能对xTX+λ求逆
在这种情况下,回归系数的计算公式将变为:W = (xTX+λI)-1XTy
这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学也叫做缩减。
#计算回归系数
def ridgeRegres(xMat, yMat, lam=0.2):
xTx = xMat.T*xMat
denom = xTx + np.eye(np.shape(xMat)[1])*lam
#将lam设为0的时候仍可能出现错误,检查行列式是否为0
if np.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 = np.mat(xArr); yMat = np.mat(yArr).T
yMean = np.mean(yMat,0)
yMat = yMat - yMean
xMeans = np.mean(xMat,0)
xVar = vars(xMat,0) #转换为字典
xMat = (xMat - xMeans) / xVar
numTestPts = 30
wMat = np.zeros((numTestPts,np.shape(xMat)[1]))
for i in range(numTestPts):
ws = ridgeRegres(wMat, yMat, np.exp(i-10))
wMat[i,:] = ws.T
return wMat
lasso:对回归系数做了限定
与岭回归的唯一不同点在于,这个约束条件使用绝对值取代了平方和
前向逐步回归:
伪代码如下:
数据标准化,使其分布满足0均值分布和单位方差
在每轮迭代过程中:
设置当前最小误差lowestError为正无穷
对每个特征:
增大或缩小:
改变一个系数得到一个新的w
计算新w下的误差
如果误差Error小于当前最小误差lowestError,设置Wbest等于当前的w
将W设置为新的Wbest
```python
#逐步线性回归算法
#输入数据xArr,预测变量yArr,eps表示每次迭代需要调整的步长,另一个numIt,表示迭代次数
def stageWise(xArr,yArr,eps=0.01,numIt=100):
#标准化处理
xMat = np.mat(xArr); yMat = np.mat(yArr).T
yMean = np.mean(yMat,0)
yMat = yMat - yMean
xMat = np.regularize(xMat)
m,n = np.shape(xMat)
returnMat = np.zeros((numIt,n))
ws = np.zeros((n,1));wsTest = ws.copy();wsMax = ws.copy() #为了实现贪心算法建立两个ws的两份副本
for i in range(numIt):
#每次迭代都打印w向量
print(ws.T)
loweastError = np.inf
for j in range(n):
for sign in [-1,1]:
wsTest = ws.copy()
wsTest[j] += np.epa*sign
yTest = xMat*wsTest
#平方误差
rssE = np.rssError(yMat.A,yTest.A)
if rssE < loweastError:
loweastError = rssE
wsMax = wsTest
ws = wsMax.copy()
returnMat[i,:] = ws.T
return returnMat
如何用缩减法确定最佳回归系数:
def crossValitation(xArr, yArr, numVal=10):
m = len(yArr)
indexList = range(m) #计算数据点m的个数
errorMat = np.zeros(numVal,30)
for i in range(m):
#创建训练集和测试机容器
trainX = [];trainY = []
testX = []; testY = []
np.random.shuffle(indexList) #将其中的元素进行混洗
for j in range(m):
if j < m*0.9: #将90%的数据集加入训练集 剩下的加入测试集
trainX.append(xArr(indexList[j]))
trainY.append(yArr(indexList[j]))
else:
testX.append(xArr[indexList[j]])
testY.append(yArr[indexList[j]])
#数据混洗完就建立一个wMat矩阵来保存岭回归中的所有回归系数
wMat = ridgeTest(trainX,trainY)
for k in range(30):
matTestX = np.mat(testX);matTrainX =np.mat(trainX)
meanTrain = np.mean(matTrainX,0)
varTrain = vars(matTrainX,0)
matTrainX = (matTestX - matTrainX)/varTrain
yEst = matTestX * np.mat(wMat[k,:].T + np.mean(trainY))
errorMat[i:k]==rssError(yEst.T.A,np.array(testY)) #计算误差,保存了每个λ对应的多个误差值
meanError = np.mean(errorMat,0) #计算误差的均值
minMean = float(min(meanError))
bestWeights = wMat(np.nonzero(meanError==minMean))
xMat = np.mat(xArr);yMat = np.mat(yArr).T
meanX = np.mean(xMat,0);varX = vars(xMat,0)
#对数据进行还原
unReg = bestWeights/varX
print("the best model from Ridge Regression is:\n",unReg)
print("with constant term:",-1*sum(np.multiply(meanX,unReg)) + np.mean(yMat))