赞
踩
线性回归
优点:结果易于理解,计算上不复杂
缺点:对非线性的数据拟合不好
使用数据类型:数值型数据和标称型数据。
python代码实现:
import numpy as np def loadDataSet(fileName): """ 加载数据集 :param fileName: 文件名 :return: dataMat:数据矩阵 labelMat:标签矩阵 """ 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): """ 线性回归 :param xArr: 输入的样本数据,包含每个样本数据的feature :param yArr: 对应于输入数据的类别标签,也就是每个样本对应的目标变量 :return: ws:回归系数 """ # np.mat()函数将xArr,yArr转换为矩阵,mat().T代表的是对矩阵进行转置操作 xMat = np.mat(xArr) yMat = np.mat(yArr).T # 矩阵乘法的条件是左矩阵的列数等于右矩阵的行数 xTx = xMat.T * xMat # 因为要用到xTx逆矩阵,所以事先需要确定计算得到的xTx是否可逆,条件是矩阵的行列式不为0 # np.linalg.det()函数是用来求得矩阵的行列式的,如果矩阵的行列式为0,则这个矩阵是不可逆的,就无法进行接下来的运算 if np.linalg.det(xTx) == 0.0: print("this matrix is singular,cannot do inverse") return # 最小二乘法 ws = xTx.I * (xMat.T * yMat) return ws
x为某个预测点,
x
(
i
)
x^{(i)}
x(i)为样本点,样本点距离预测点越近,贡献的误差越大(权值越大),越远则贡献的误差越小(权值越小)。
python代码实现:
def lwlr(testPoint, xArr, yArr, k=1.0): """ 局部加权线性回归,在待预测点附近的每一个点赋予一定的权重,在子集上基于最小均方差来进行普通的回归 :param testPoint:样本点 :param xArr:样本的特征数据,即feature :param yArr:每个样本对应的类别标签,即目标变量 :param k:关于赋予权重矩阵的核的每一个参数,与权重的衰减速率有关 :return: testPoint*ws:数据点与具有权重的系数相乘得到的预测点 """ xMat = np.mat(xArr) yMat = np.mat(yArr).T row = np.shape(xMat)[0] # eye()返回一个对角线元素为1,其他元素为0的二维数组,创建传递矩阵weights weights = np.mat(np.eye(row)) for j in range(row): # testPoint的形式是一个行向量 # 计算testPoint与输入样本点之间的距离,然后下面计算出每个样本贡献误差的权值 diffMat = testPoint - xMat[j, :] # k控制衰减的速度 weights[j, j] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2)) # 根据矩阵乘法计算xTx,其中的weights矩阵是样本点对应的权值矩阵 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): """ 测试局部加权线性回归函数 :param testArr:测试样本点 :param xArr:样本的特征数据,即feature :param yArr:每个样本对应的类别标签,即目标变量 :param k:关于赋予权重矩阵的核的每一个参数,与权重的衰减速率有关 :return: """ row = np.shape(testArr)[0] yHat = np.zeros(row) for i in range(row): yHat[i] = lwlr(testArr[i], xArr, yArr, k) return yHat
def rssError(yArr, yHatArr): return ((yArr - yHatArr) ** 2).sum() if __name__ == "__main__": abX, abY = loadDataSet('abalone.txt') print("训练集与测试集相同:局部加权线性回归") yHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1) yHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1) yHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10) print('k=0.1时,误差大小为:', rssError(abY[0:99], yHat01.T)) print('k=1时,误差大小为:', rssError(abY[0:99], yHat1.T)) print('k=10时,误差大小为:', rssError(abY[0:99], yHat10.T)) print('') print("训练集与测试集不同:局部加权线性回归") yHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1) yHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1) yHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10) print('k=0.1时,误差大小为:', rssError(abY[100:199], yHat01.T)) print('k=1时,误差大小为:', rssError(abY[100:199], yHat1.T)) print('k=10时,误差大小为:', rssError(abY[100:199], yHat10.T)) print('') print("训练集与测试集不同:简单的线性回归与k=1时的局部加权线性回归对比:") print('k=1时,误差大小为:', rssError(abY[100:199], yHat1.T)) ws = standRegres(abX[0:99], abY[0:99]) yHat = np.mat(abX[100:199]) * ws print('简单的线性回归误差大小:', rssError(abY[100:199], yHat.T.A)) plt.show()
python代码实现
def ridgeRegres(xMat, yMat, lam=0.2): """ :param xMat: :param yMat: :param lam: :return: """ xTx = xMat.T * xMat denom = xTx + np.eye(np.shape(xMat)[1]) * lam if np.linalg.det(denom) == 0.0: print("this matrix is singular,cannot do inverse") ws = np.linalg.pinv(denom) * (xMat.T * yMat) ws = denom.I * (xMat.T * yMat) return ws def ridgeTest(xArr, yArr): """ :param xArr: :param yArr: :return: """ xMat = np.mat(xArr) yMat = np.mat(yArr).T yMean = np.mean(yMat, 0) yMat = yMat - yMean xMeans = np.mean(xMat, 0) xVar = np.var(xMat, 0) xMat = (xMat - xMeans) / xVar numTestPts = 30 wMat = np.zeros((numTestPts, np.shape(xMat)[1])) for i in range(numTestPts): ws = ridgeRegres(xMat, yMat, np.exp(i - 10)) wMat[i, :] = ws.T return wMat if __name__ == "__main__": abX, abY = loadDataSet('abalone.txt') ridgeWeights = ridgeTest(abX,abY) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(ridgeWeights) plt.show()
回归系数与log(λ)的关系,最左边λ最小时,8个系数的原始值与线性回归一样,最右边8个回归系数全部缩减为0,为找到最佳参数λ,还需要将ws乘以测试集比较原始测试集对比误差大小。0对应
λ
=
e
x
p
(
0
−
10
)
\lambda = exp(0-10)
λ=exp(0−10),30对应
λ
=
e
x
p
(
30
−
10
)
\lambda=exp(30-10)
λ=exp(30−10)
在增加约束:所有回归系数的平方和不能大于λ的条件下、普通的最小二乘法回归会得到与岭回归一样的公式
∑
k
=
1
n
ω
k
2
⩽
λ
\sum_{k=1}^n\omega_k^2\leqslant\lambda
k=1∑nωk2⩽λ
与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下:
∑
k
=
1
n
∣
ω
k
∣
⩽
λ
\sum_{k=1}^n|\omega_k|\leqslant\lambda
k=1∑n∣ωk∣⩽λ
逐步线性回归算法的主要优点在于它可以帮助人们理解现有的模型并作出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。
当应用缩减方法(如逐步线性回归或岭回归)时,模型也就增加了偏差(bias),与此同时减小了模型的方差(variance)
模型和测量值之间存在的差异,叫做误差error。当考虑模型中存在“噪声”或者说误差时,必须考虑其来源。
方差度量了同样大小的训练集的变动所导致的学习性能的变化, 即 刻画了数据扰动所造成的影响
偏差度量了学习算法的期望预测与真实结果的偏离程度,即 刻画了学习算法本身的拟合能力
噪声表达了在当前任务上任何学习算法所能达到的期望泛化误差的下界, 即 刻画了学习问题本身的难度
from time import sleep import json import urllib def searchForSet(retX,retY,setNum,yr,numPce,origPrc): sleep(10) myAPIstr = 'get from code.google.com' searchURL = 'https://www.googleapis.com/shopping/search/v1/public/products?key=%s&country=US&q=lego+%d&alt=json' % (myAPIstr, setNum) pg = urllib.request.urlopen(searchURL) retDict = json.loads(pg.read()) for i in range(len(retDict['items'])): try: currItem = retDict['items'][i] if currItem['product']['condition'] == 'new': newFlag = 1 else: newFlag = 0 listOfInv = currItem['product']['inventories'] for item in listOfInv: sellingPrice = item['price'] if sellingPrice > origPrc * 0.5: print ("%d\t%d\t%d\t%f\t%f" % (yr,numPce,newFlag,origPrc, sellingPrice)) retX.append([yr, numPce, newFlag, origPrc]) retY.append(sellingPrice) except: print ('problem with item %d' % i) def setDataCollect(retX, retY): searchForSet(retX, retY, 8288, 2006, 800, 49.99) searchForSet(retX, retY, 10030, 2002, 3096, 269.99) searchForSet(retX, retY, 10179, 2007, 5195, 499.99) searchForSet(retX, retY, 10181, 2007, 3428, 199.99) searchForSet(retX, retY, 10189, 2008, 5922, 299.99) searchForSet(retX, retY, 10196, 2009, 3263, 249.99) def crossValidation(xArr,yArr,numVal=10): m = len(yArr) indexList = list(range(m)) #创建numVal*30的误差矩阵 ##30的由来:ridgeTest()使用了30个不同的lambda值来创建不同的回归系数,即numTestPts = 30 errorMat = np.zeros((numVal,30)) for i in range(numVal): #创建测试集和训练集容器 trainX=[]; trainY=[] testX = []; testY = [] #打乱索引顺序,实现随机选取训练集和测试集数据点 np.random.shuffle(indexList) #90%训练+10%测试 for j in range(m): if j < m*0.9: trainX.append(xArr[indexList[j]]) trainY.append(yArr[indexList[j]]) else: testX.append(xArr[indexList[j]]) testY.append(yArr[indexList[j]]) wMat = ridgeTest(trainX,trainY) #获得30组ws向量 for k in range(30): matTestX = np.mat(testX); matTrainX=np.mat(trainX) #用训练集参数将测试集数据标准化 meanTrain = np.mean(matTrainX,0) varTrain = np.var(matTrainX,0) matTestX = (matTestX-meanTrain)/varTrain yEst = matTestX * np.mat(wMat[k,:]).T + np.mean(trainY) errorMat[i,k]=np.rssError(yEst.T.A,np.array(testY)) #print errorMat[i,k] #计算不同岭回归ws下errorMat的平均值,观察平均性能 #meanErrors:1*30矩阵 meanErrors = np.mean(errorMat,0) minMean = float(min(meanErrors)) #nonzero(meanErrors==minMean)返回的是误差最小的索引,因此bestWeights为误差最小的那个w向量 bestWeights = wMat[np.nonzero(meanErrors==minMean)] #岭回归使用了数据标准化,而standRegres没有,为了比较可视化,因此需要将数据还原 #标准化后 Xreg = (x-meanX)/var(x),预测y=Xreg*w+meanY #因此,利用未标准化的x来计算y= x*w/var(x) - meanX*w/var(x) +meanY #其中unReg=w/var xMat = np.mat(xArr); yMat=np.mat(yArr).T meanX = np.mean(xMat,0); varX = np.var(xMat,0) unReg = bestWeights/varX #print ("the best model from Ridge Regression is:\n",unReg) #特别注意这里的sum函数,一定是np.sum,因为一般的sum只能对list求和,而这里的参数是matrix #print ("with constant term: ",-1*np.sum(multiply(meanX,unReg)) + mean(yMat)) yHat=xMat*unReg.T-1*np.sum(np.multiply(meanX,unReg)) + np.mean(yMat) return yHat
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。