回归主要用来解决数值预测问题,给定数据集D={(xi, yi)} ,xi={xi1,xi2...xid} 即每个样本有d个属性,求出x与y的最佳拟合曲线。
1.线性回归
假设x与y之间存在线性关系:
将数据矩阵进行处理,添加x0=1这一项,将b看成w参数的一部分,即:
若使线性方程能够很好地你和所有点,这里使用均方误差作为优化目标:
令 对于W求导有:
导数等于零,可以解得:
其中当XTX是满秩矩阵时。
若XTX不是满秩,一般通过引入正则化的方式来求解。
数据集准备: 数据X只有一个属性特征 第一列为处理加入的数据
加载数据集 转换成数据矩阵X以及类别向量Y
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 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
绘出数据集分布以及最佳拟合曲线图:
def plot(xArr, yArr, ws):
xMat = mat(xArr)
yMat = mat(yArr)
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:,0].flatten().A[0])
xCopy = xMat.copy()
xCopy.sort(0)
yHat = xCopy*ws
ax.plot(xCopy[:,1], yHat)
plt.show()
首先绘出数据集的分布,然后将X排序,再与回归系数ws相乘,得到样本点的预测值,画出最佳拟合曲线
预测值yHat与真实值yMat的匹配程度,使用相关系数来计算:
协方差:如果两个变量的变化趋势一致,其中一个大于自身的期望值时另外一个也大于自身的期望值,两个变量之间的协方差就是正值;如果两个变量的变化趋势相反,即其中一个变量大于自身的期望值时另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。
相关系数:相关系数是用以反映变量之间相关关系密切程度的统计指标。相关系数也可以看成协方差:一种剔除了两个变量量纲影响、标准化后的特殊协方差,它消除了两个变量变化幅度的影响,而只是单纯反应两个变量每单位变化时的相似程度。
计算结果如下所示:
当数据集并不是线性关系时,拟合效果不好,容易欠拟合。
2.局部加权线性回归LWLR
高斯核:对于靠近测试点的样本点,赋予更大的权值。距离测试点越远的样本点,权值越小。
k的取值影响了权重大小的分配情况
局部加权线性回归的模型:
最终解:
其中W为只含对角元素的权重矩阵,给与数据点的附近点赋予相应的权重。
求解LWLR,求出回归系数以及权重矩阵,给出预测值
def lwlr(testPoint,xArr,yArr,k=1.0):
xMat = mat(xArr); yMat = mat(yArr).T
m = shape(xMat)[0]
#声明一个对角矩阵 对角线为1 其余为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
eye生成一个对角矩阵 对角为1其余为0.高斯核,当样本向量X多维时,应该计算向量的模。
结合数据集D,绘出数据分布以及拟合曲线
def lwlrTest(testArr,xArr,yArr,k=1.0): #loops over all the data points and applies lwlr to each one
m = shape(testArr)[0]
yHat = zeros(m)
#返回样本集的预测值
for i in range(m):
yHat[i] = lwlr(testArr[i],xArr,yArr,k)
return yHat
def lwlrplot(k):
xArr, yArr = loadDataSet('ex0.txt')
xMat = mat(xArr)
yMat = mat(yArr)
yHat = lwlrTest(xArr, xArr, yArr, k)
srtInd = xMat[:,1].argsort(0)
#print(srtInd)
xSort = xMat[srtInd][:,0,:]
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xSort[:,1], yHat[srtInd])
ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:,0].flatten().A[0], s=2, c='red')
plt.show()
x.argsort() 将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y
改变高斯核参数K,从1,0.01以及0.003可以任意k=0.01时拟合较好,第一种出现欠拟合 第三种出现过拟合
LWLR增加了计算量,每次都必须使用整个数据集
下面以鲍鱼数据进行测试比较
数据集样本如下:
平方误差之和的实现:
这里不需要平均m
def rssError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
return ((yArr-yHatArr)**2).sum()
采用LWLR,前100行作为训练样本,后100行作为测试样本,改变高斯核来观察曲线的拟合程度:
def testRssError():
abX, abY = loadDataSet('abalone.txt')
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('train error k = 0.1 ', rssError(abY[0:99], yHat01.T))
print('train error k = 1 ', rssError(abY[0:99], yHat1.T))
print('train error k = 10 ', rssError(abY[0:99], yHat10.T))
可知随着k的减小,平方误差越来越小,当K过于小时,易出现过拟合。
在测试集上,K很小时,误差很大,说明出现了过拟合。最后一项为线性回归的误差分析。