当前位置:   article > 正文

机器学习实践——预测数值型数据:回归_模型预测值为常数

模型预测值为常数

线性回归过程就是:将输入项乘上一些常量,然后再累加起来,就得到预测值。那么如何找到这些常量呢?

求解这些回归系数的过程就是回归。

根据回归过程,可以得到一般公式:

               Y = wT*x 

现在问题是,我们有x的值和y的值,如何求出向量w的值,常用的方法就是是误差最小的 w,所以采用平方误差

                           

对W进行求导,令其为零,解出W如下:

值得注意的是,上述公式包含对矩阵的求逆,那么如果该矩阵的行列式等于0,就不可逆,所以必须先判断矩阵是否可逆。

注:求解W的方法是统计学常用的方法,称之为最小二乘法(least square)

求解W的代码:

  1. #加载数据
  2. def loadDataSet(filename):
  3. fr = open(filename)
  4. numFeat = len(fr.readline().strip().split('\t')) - 1
  5. dataMat = []; labelMat = []
  6. for line in fr.readlines():
  7. lineArr = []
  8. currLine = line.strip().split('\t')
  9. for i in range(numFeat):
  10. lineArr.append(float(currLine[i]))
  11. dataMat.append(lineArr)
  12. labelMat.append(float(currLine[-1]))
  13. return dataMat,labelMat
  14. #计算W
  15. def standRegers(xArr,yArr):
  16. #首先转换为矩阵,方便计算
  17. xMat = mat(xArr)
  18. yMat = mat(yArr).T
  19. xTx = xMat.T * xMat
  20. #判断矩阵的行列式是否为0
  21. if linalg.det(xTx) == 0.0:
  22. print "这个矩阵没有逆矩阵"
  23. return
  24. #求出W
  25. ws = xTx.I * (xMat.T * yMat)
  26. return ws

通过matplotlib将数据可视化,并画出最佳拟合直线

  1. #加载数据
  2. xArr, yArr = loadDataSet('Ch08/ex0.txt')
  3. ws = standRegers(xArr,yArr)
  4. #转换为矩阵
  5. xMat = mat(xArr)
  6. yMat = mat(yArr)
  7. #预测的y值
  8. yHat = xMat*ws
  9. fig = plt.figure()
  10. axes = fig.add_subplot(111)
  11. axes.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0])
  12. #将xMat的值复制一份,将x的排序,避免直线上的点出现混乱
  13. xCopy = xMat.copy()
  14. xCopy.sort(0)
  15. yHat = xCopy * ws
  16. axes.plot(xCopy[:,1],yHat)
  17. plt.show()

实验结果:

局部加权线性回归

线性回归的一个问题就是容易出现欠拟合的现象,就比如上图的实验结果,数据点分明是弯曲向上的,结果预测结果是直线,虽然也不错,但是结果能不能更好呢?其中一个方法就是局部加权线性回归,我们给预测点附近的每个点赋予一定权重,

回归系数:

                    

其中的W是一个矩阵,用来给每个数据点赋予权重,该算法使用高斯核对附近的点赋予更高的权重,高斯核的权重如下:

                

代码实现局部加权线性回归函数

  1. #testpoint是一个测试点,k是高斯核的参数,决定了对附近的点赋予多大的权重
  2. #函数作用:给定x空间的任意一点,求出对应的预测值yHat
  3. def lwlr(testPoint,xArr,yArr,k=1.0):
  4. xMat = mat(xArr)
  5. yMat = mat(yArr).T
  6. m = shape(xMat)[0]
  7. #初始化权重为1,eye返回一个单位矩阵
  8. weights = mat(eye(m))
  9. #求出高斯核权重
  10. for j in range(m):
  11. diffMat = testPoint - xMat[j,:]
  12. weights[j,j] = exp(diffMat * diffMat.T/(-2.0 * k**2))
  13. xTx = xMat.T * (weights * xMat)
  14. if linalg.det(xTx) == 0.0:
  15. print "该矩阵无法求逆"
  16. return
  17. ws = xTx.I * (xMat.T * (weights * yMat))
  18. #返回预测值yHat
  19. return testPoint * ws
  20. #用于为没个数据点调用lwlr函数
  21. def lwlrTest(testArr,xArr,yArr,k=1.0):
  22. m = shape(testArr)[0]
  23. yHat = zeros(m)
  24. for i in range(m):
  25. yHat[i] = lwlr(testArr[i],xArr,yArr,k)
  26. return yHat

利用matplotlib将数据可视化:

  1. x, y = loadDataSet('Ch08/ex0.txt')
  2. #print y[0]
  3. #print lwlr(x[0],x,y,0.001)
  4. yHat = lwlrTest(x,x,y,0.003)
  5. x = mat(x)
  6. srtInd = x[:,1].argsort(0)
  7. xSort = x[srtInd][:,0,:]
  8. fig = plt.figure()
  9. axes = fig.add_subplot(111)
  10. axes.plot(xSort[:,1],yHat[srtInd])
  11. axes.scatter(x[:,1].flatten().A[0],mat(y).T[:,0].flatten().A[0],
  12. s = 2,c = 'red')
  13. plt.show()

实验结果

k=1.0时

k=0.003时

k=0.01时

实验可得:k=1.0时和最小二乘法差不对,k=0.003时则考虑了太多的噪声点,出现了过拟合的现象,k=0.01时模型与样本点基本吻合,可以挖掘许多潜在的价值。

示例:预测鲍鱼的年龄

我们使用一种函数rssError来计算预测值与实际值之间的误差

  1. def rssError(yArr,yHatArr):
  2. return ((yArr - yHatArr)**2).sum()
  1. abX,abY = loadDataSet('Ch08/abalone.txt')
  2. #k值分别取0.1 1.0 10 来比较较好的高斯核
  3. yHat01 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],0.1)
  4. yHat1 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],1)
  5. yHat10 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],10)
  6. #对已知的数据计算误差
  7. print 'k=0.1预测已知数据\t',rssError(abY[0:99],yHat01.T)
  8. print 'k=1.0预测已知数据\t',rssError(abY[0:99],yHat1.T)
  9. print 'k=10预测已知数据\t',rssError(abY[0:99],yHat10.T)
  10. yHat01 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],0.1)
  11. yHat1 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],1)
  12. yHat10 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],10)
  13. #对未知的数据计算误差
  14. print 'k=0.1预测未知数据\t',rssError(abY[100:199],yHat01.T)
  15. print 'k=1.0预测未知数据\t',rssError(abY[100:199],yHat1.T)
  16. print 'k=10预测未知数据\t',rssError(abY[100:199],yHat10.T),"\n"

实验结果:

可以看到在对已知的数据进行预测时,核(k)的值越小越好,因为更加拟合,但是在对未知的数据进行预测时,表现都较差,并且k值越小反而越差。也就是说这种方法,每次必须在整个数据集上运行,要训练所有的数据才行。

缩减系数来“理解”数据

现在考虑一个问题,如果特征比样本还多怎么办?n>m,输入矩阵不再是满秩矩阵,在求逆过程中会出错。

为了解决这一问题,提出岭回归,除此之外还有lasso法以及前项逐步回归

岭回归

岭回归就是在矩阵上加入一个,从而使得矩阵是可以求逆,所以计算公式就变成了这样

            

求解的公式变为

这新增的一项就称之为惩罚项,能够减少不必要的参数,也称之为 缩减

代码部分:

  1. #计算加入惩罚项后的w,lam是加入的单位矩阵的系数,这里定义为0.2
  2. def ridgeRegres(xMat,yMat,lam = 0.2):
  3. xTx = xMat.T * xMat
  4. denom = xTx + eye(shape(xMat)[1]) * lam
  5. #仍然判断是否可逆,如果lam=0,那么相当于没有加入惩罚项
  6. if linalg.det(denom) == 0.0:
  7. print "矩阵不可逆"
  8. return
  9. ws = denom.I *(xMat.T * yMat)
  10. return ws
  11. #通过设置不同的lam,对结果造成怎样的影响
  12. def ridgeRegresTest(xArr,yArr):
  13. xMat = mat(xArr)
  14. yMat = mat(yArr).T
  15. #数据标准化,为了让数据对结果的影响是一致的,
  16. # 类似于概率论中的数据标准化,
  17. ymean = mean(yMat,0)
  18. yMat = yMat - ymean
  19. xmeans = mean(xMat,0)
  20. #取xMat的方差
  21. xVar = var(xMat,0)
  22. #(x-均值)/方差
  23. xMat = (xMat-xmeans)/xVar
  24. #设置迭代次数
  25. numTestPts = 30
  26. wMat = zeros((numTestPts,shape(xMat)[1]))
  27. for i in range(numTestPts):
  28. #记录不同的lam值带来的效果,lam的值是指数变化
  29. ws = ridgeRegres(xMat,yMat,exp(i-10))
  30. wMat[i,:] = ws.T
  31. return wMat

实验结果

可以看到,当lam非常小的时候,系数与普通回归一样,而lam非常大的时候,所有的回归系数都变为0,可以在中间某处找到一个使得预测结果最好的lam的值。

前向逐步回归

前向逐步回归算法属于一种贪心算法,即每一步都尽可能减少误差。一开始,所有的权重都设置为1,然后每一步所做的决策是对某个权重增加或减少一个很小的值。

 

代码:

  1. #数据标准化
  2. def regularize(xMat):#regularize by columns
  3. inMat = xMat.copy()
  4. inMeans = mean(inMat,0)
  5. inVar = var(inMat,0)
  6. inMat = (inMat - inMeans)/inVar
  7. return inMat
  8. def stageWise(xArr,yArr,eps = 0.01,numIt = 100):
  9. xMat = mat(xArr);yMat = mat(yArr).T
  10. ymean = mean(yMat,0)
  11. yMat = yMat - ymean
  12. xMat = regularize(xMat)
  13. m,n = shape(xMat)
  14. returnMat = zeros((numIt,n))
  15. ws = zeros((n,1))
  16. wsTest = ws.copy()
  17. wsMax = ws.copy()
  18. #对每一次迭代
  19. for i in range(numIt):
  20. print ws.T
  21. #初始设最小误差为无穷大
  22. lowestError = inf
  23. #对每个特征
  24. for j in range(n):
  25. #增加或是减少
  26. for sign in [-1,1]:
  27. wsTest = ws.copy()
  28. wsTest[j] +=eps*sign
  29. yTest = xMat *wsTest
  30. #计算误差
  31. rssE = rssError(yMat.A,yTest.A)
  32. #将最小误差记录下来
  33. if rssE <lowestError:
  34. lowestError = rssE
  35. wsMax = wsTest
  36. ws = wsMax.copy()
  37. returnMat[i,:] = ws.T
  38. return returnMat

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/829884
推荐阅读
相关标签
  

闽ICP备14008679号