机器学习-线性回归

一、用线性回归预测最佳拟合直线

       回归的目的是用已知的回归方程预测数值型的目标值,求回归方程系数的过程叫做回归。具体的做法是用回归系数乘以输入值,再将结果全部加起来,就得到预测值。
  
  求回归系数的一个常用方法是找出使得误差最小的 w w w,这里的误差指的是预测 y y y值和真实 y y y值之间的差值,使用误差的简单累加正差值和负差值相互抵消,所以采用平方误差,而基于均方误差最小化来进行模型求解的方法称为“最小二乘法”。其中平方误差可以写为:
                       
                        E w = ∑ i = 1 m ( y i − x i w ) 2 E_{w}=\sum_{i=1}^{m}(y_{i}-x_{i}w)^{2} Ew=i=1m(yixiw)2
  
  用矩阵表示还可以写作 E w = ( y − X w ) T ( y − X w ) E_{w}=(y-Xw)^{T}(y-Xw) Ew=(yXw)T(yXw),对 w w w求导得:
  
                      E w = y T y − w T X T y − y X w + w T X T X w E_{w}=y^{T}y-w^{T}X^{T}y-yXw+w^{T}X^{T}Xw Ew=yTywTXTyyXw+wTXTXw
  
                      ∂ ∂ w E w = − X T y − X T y + X T X w + X T X w \frac{\partial }{\partial w}E_{w}=-X^{T}y-X^{T}y+X^{T}Xw+X^{T}Xw wEw=XTyXTy+XTXw+XTXw
  
                      ∂ ∂ w E w = 2 X T X w − 2 X T y = 2 X T ( X w − y ) \frac{\partial }{\partial w}E_{w}=2X^{T}Xw-2X^{T}y=2X^{T}(Xw-y) wEw=2XTXw2XTy=2XT(Xwy)
 
  这里用到对矩阵的转置求导,即: ∂ ∂ A A B = ∂ ∂ A B A = B T \frac{\partial }{\partial A}AB=\frac{\partial }{\partial A}BA=B^{T} AAB=ABA=BT, ∂ ∂ A A T B = ∂ ∂ A B A T = B \frac{\partial }{\partial A}A^{T}B=\frac{\partial }{\partial A}BA^{T}=B AATB=ABAT=B
  
  令 ∂ ∂ w E w = 0 \frac{\partial }{\partial w}E_{w}=0 wEw=0可得 w w w的最优的闭式解,当 X T X X^{T}X XTX为满秩矩阵或者正定矩阵时可得:
                           
                           w = ( X T X ) − 1 X T y w=(X^{T}X)^{-1}X^{T}y w=(XTX)1XTy
基于Python实现的代码如下所示:

def standRegres(xArr,yArr):
    xMat=mat(xArr);yMat=mat(yArr)
    xTx=xMat.T*xMat               #计算X.T*X
    if linalg.det(xTx)==0.0:
        print("This matrix is singular,cannot do inverse")
        return
    ws=xTx.I*(xMat.T*yMat.T)       #xTx.I为xTx的逆
    return ws

画出数据集和最佳拟合直线Python代码如下所示:

def plotScatter(xArr,yArr,ws):
    xMat=mat(xArr)
    yMat=mat(yArr)
    yHat=xMat*ws
    coef=corrcoef(yHat.T,yMat)      #计算相关系数
    print("相关系数为:",coef)
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0],c='r',s=10)  #flatten函数将矩阵降成一维,.A表示将矩阵转换成数组
    xCopy=xMat.copy()
    xCopy.sort(0)                 #按列排序结果
    yHat=xCopy*ws
    ax.plot(xCopy[:,1],yHat)
    plt.savefig('最佳拟合直线示意图.png')
    plt.show()

得到的结果如下图所示:
在这里插入图片描述

二、局部加权线性回归

       线性回归可能出现欠拟合现象,因为它要求的是具有最小均方误差的无偏估计。如果模型欠拟合则不能去的较好的预测效果。所以局部加权线性回归在估计中引入一些偏差,从而降低预测的均方误差。
  
  在局部加权线性回归(LWLR)算法中,给带预测的点附近的每一个点赋予一定的权重,在这个子集上基于最小均方误差进行普通回归。与KNN一样,该算法每次预测均需要事先选取出对应的数据子集,该算法解出回归系数 w w w的形式如下:
                      
                       w = ( X t W X ) − 1 X T W y w=(X^{t}WX)^{-1}X^{T}Wy w=(XtWX)1XTWy

其中 W W W是一个矩阵,用来给每个数据点赋予权重。
  
  局部加权线性回归使用"核"来对附近的点赋予更高的权重。最常用的就是高斯核,高斯核对应的权重如下所示:
                       
                        w ( i , i ) = e x p ( ∣ x i − x ∣ − 2 k 2 ) w(i,i)=exp\left ( \frac{\left | x^{i}-x \right |}{-2k^{2}} \right ) w(i,i)=exp(2k2xix)
  
  这样就构建了一个只含对角线元素的权重矩阵 W W W,并且点 x x x x ( i ) x(i) x(i)越近, w ( i , i ) w(i,i) w(i,i)将会越大。 k k k为用户指定的参数,它决定对附近点赋予多大的权重。

基于Python实现局部加权线性回归以及画出拟合直线的代码如下所示:

def lwlr(testPoint,xArr,yArr,k=1.0):
    xMat=mat(xArr);yMat=mat(yArr)
    m=shape(xMat)[0]
    weights=mat(eye((m)))                             #创建对角矩阵(方阵),阶数等于样本点的个数,即为每个样本点初始化一个权重
    for j in range(m):                                #算法遍历数据集,计算每一个样本点对应的权重值
        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.T))
    return testPoint*ws                               #得到回归系数ws的一个估计

def lwlrTest(testArr,xArr,yArr,k=1.0):
    m=shape(testArr)[0]
    yHat=zeros(m)
    for i in range(m):
        yHat[i]=lwlr(testArr[i],xArr,yArr,k)          #给定空间中的任意一点,计算出对应的预测值yHat
    return yHat

def plotScatterlwlr(xArr,yArr,yHat):
    xMat = mat(xArr)
    yMat = mat(yArr)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xMat[:, 1].flatten().A[0], yMat.flatten().A[0], c='r', s=2)  # flatten函数将矩阵降成一维
    srtInd=xMat[:,1].argsort(0)
    xSort=xMat[srtInd][:,0,:]                                               #返回的是数组值从小到大的索引值
    ax.plot(xSort[:,1], yHat[srtInd])
    plt.savefig('k=0.01时局部加权线性回归示意图.png')
    plt.show()

k = 0.01 时 k=0.01时 k=0.01,拟合的直线结果如下所示
在这里插入图片描述
k = 0.003 k=0.003 k=0.003考虑了太多的噪声,从而出现过拟合现象,拟合直线如下图所示:
在这里插入图片描述
k = 1 k=1 k=1时,拟合的效果与最小二乘法差不多
在这里插入图片描述

三、岭回归

       当特征比样本点还多 ( n > m ) (n>m) (n>m),也就是说矩阵 X X X不是满秩的,非满秩矩阵在求逆时会出现问题。统计学家引入了岭回归的概念。简单来说岭回归就是在矩阵 X T X X^{T}X XTX上加一个 λ I \lambda I λI,从而使得矩阵非奇异,进而能使得 ( X T X + λ I ) (X^{T}X+\lambda I) (XTX+λI)求逆。其中 I I I是一个 m ∗ m m*m mm的单位矩阵。在这种情况下回归系数的计算公式变为:
                       
                       w = ( X T X + λ I ) − 1 X T y w=(X^{T}X+\lambda I)^{-1}X^{T}y w=(XTX+λI)1XTy
  
  这里通过引入 λ \lambda λ来限制所有 w w w之和,通过引入该惩罚项,能够减少不重要的参数。岭回归以及回归系数变化图实现代码如下所示:

#岭回归
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,connot do inverse')
        return
    ws=denom.I*(xMat.T*yMat.T)
    return  ws

def ridgeTest(xArr,yArr):
    xMat=mat(xArr);yMat=mat(yArr)
    yMean=mean(yMat.T,0)
    yMat=yMat-yMean
    xMeans=mean(xMat,0)
    xVar=var(xMat,0)
    xMat=(xMat-xMeans)/xVar
    numTestPts=30
    wMat=zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        ws=ridgeRegres(xMat,yMat,exp(i-10))
        wMat[i,:]=ws.T
    return wMat

def plotRidge(ridgeWeights):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.plot(ridgeWeights)
    plt.savefig('岭回归的回归系数变化图.png')
    plt.show()

岭回归的系数变化图如下所示:
在这里插入图片描述

四、前向逐步回归

       前向逐步回归属于一种贪心算法,对每一步都尽可能的减少误差。其伪代码如下所示:
      
      数据标准化,使其分布满足0均值和单位方差
      在每轮迭代过程中:
        设置当前最小误差lowestError为正无穷
        对每个特征:
          增大或者缩小:
          改变一个系数得到一个新的w
          计算新的w下的误差
          如果误差Error小于最小当前误差lowestError:
             设置wbest等于当前的w
          将w设置为新的wbest

  
  基于Python 实现的代码如下所示:

def stageWise(xArr,yArr,eps,numIt):

    #数据标准化
    xMat=mat(xArr);yMat=mat(yArr).T
    yMean=mean(yMat,0)
    yMat=yMat-yMean
    xMeans=mean(xMat,0)
    xVar=var(xMat,0)
    xMat=(xMat-xMeans)/xVar
    m,n=shape(xMat)
    returnMat=zeros((numIt,n))
    ws=zeros((n,1))
    wsTest=ws.copy()
    wsMax=ws.copy()

    #每轮迭代过程
    for i in range(numIt):
        print(ws.T)
        lowesError=inf
        for j in range(n):
            for sign in [-1,1]:
                wsTest=ws.copy()
                wsTest[j]+=eps*sign
                yTest=xMat*wsTest
                rssE=rssError(yMat.A,yTest.A)
                if rssE<lowesError:
                    lowesError=rssE
                    wsMax=wsTest
        ws=wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat

#分析预测误差大小
def rssError(yArr,yHatArr):
    return((yArr-yHatArr)**2).sum()

def plotlasso(returnWeights):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.plot(returnWeights)
    plt.savefig('前向逐步回归系数变化图.png')
    plt.show()

前向逐步回归得到的系数与迭代次数的关系如下所示:
在这里插入图片描述

五、全部代码实现

工程打包地址:

"""
内容:
1.机器学习-回归分析
2.标准回归函数
3.局部加权线性回归
4.岭回归
5.前向逐步回归
姓名:pcb
日期:2019.1.6
"""
from numpy import *
import matplotlib.pyplot as plt


#加载数据
def loadDataSet(filename):
    numFeat=len(open(filename).readline().split('\t'))-1
    datMat=[];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]))
        datMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return datMat,labelMat

#1.---------------计算最佳拟合直线---------------------------------------------
def standRegres(xArr,yArr):
    xMat=mat(xArr);yMat=mat(yArr)
    xTx=xMat.T*xMat               #计算X.T*X
    if linalg.det(xTx)==0.0:
        print("This matrix is singular,cannot do inverse")
        return
    ws=xTx.I*(xMat.T*yMat.T)       #xTx.I为xTx的逆
    return ws

#画出线性回归的散点图以及最佳拟合曲线
def plotScatter(xArr,yArr,ws):
    xMat=mat(xArr)
    yMat=mat(yArr)
    yHat=xMat*ws
    coef=corrcoef(yHat.T,yMat)      #计算相关系数
    print("相关系数为:",coef)
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0],c='r',s=10)  #flatten函数将矩阵降成一维,.A表示将矩阵转换成数组
    xCopy=xMat.copy()
    xCopy.sort(0)                 #按列排序结果
    yHat=xCopy*ws
    ax.plot(xCopy[:,1],yHat)
    plt.savefig('最佳拟合直线示意图.png')
    plt.show()

#-----------------------------------------------------------------------------

#2.----------------局部加权线性回归---------------------------------------------
def lwlr(testPoint,xArr,yArr,k=1.0):
    xMat=mat(xArr);yMat=mat(yArr)
    m=shape(xMat)[0]
    weights=mat(eye((m)))                             #创建对角矩阵(方阵),阶数等于样本点的个数,即为每个样本点初始化一个权重
    for j in range(m):                                #算法遍历数据集,计算每一个样本点对应的权重值
        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.T))
    return testPoint*ws                               #得到回归系数ws的一个估计

def lwlrTest(testArr,xArr,yArr,k=1.0):
    m=shape(testArr)[0]
    yHat=zeros(m)
    for i in range(m):
        yHat[i]=lwlr(testArr[i],xArr,yArr,k)          #给定空间中的任意一点,计算出对应的预测值yHat
    return yHat

def plotScatterlwlr(xArr,yArr,yHat):
    xMat = mat(xArr)
    yMat = mat(yArr)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xMat[:, 1].flatten().A[0], yMat.flatten().A[0], c='r', s=2)  # flatten函数将矩阵降成一维
    srtInd=xMat[:,1].argsort(0)
    xSort=xMat[srtInd][:,0,:]                                               #返回的是数组值从小到大的索引值
    ax.plot(xSort[:,1], yHat[srtInd])
    plt.savefig('k=0.01时局部加权线性回归示意图.png')
    plt.show()

#-----------------------------------------------------------------------------

#3.----------使用岭回归---------------------------------------------------------


#岭回归
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,connot do inverse')
        return
    ws=denom.I*(xMat.T*yMat.T)
    return  ws

def ridgeTest(xArr,yArr):
    xMat=mat(xArr);yMat=mat(yArr)
    yMean=mean(yMat.T,0)
    yMat=yMat-yMean
    xMeans=mean(xMat,0)
    xVar=var(xMat,0)
    xMat=(xMat-xMeans)/xVar
    numTestPts=30
    wMat=zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        ws=ridgeRegres(xMat,yMat,exp(i-10))
        wMat[i,:]=ws.T
    return wMat

def plotRidge(ridgeWeights):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.plot(ridgeWeights)
    plt.savefig('岭回归的回归系数变化图.png')
    plt.show()

#-----------------------------------------------------------------------------

#-----------前向逐步回归-------------------------------------------------------
"""
伪代码:
    数据标准化,使其分布满足0均值和单位方差
    在每轮迭代过程中:
        设置当前最小误差lowestError为正无穷
        对每个特征:
            增大或者缩小:
               改变一个系数得到一个新的w
               计算新的w下的误差
               如果误差Error小于最小当前误差lowestError:
                   设置wbest等于当前的w
            将w设置为新的wbest

"""
def stageWise(xArr,yArr,eps,numIt):

    #数据标准化
    xMat=mat(xArr);yMat=mat(yArr).T
    yMean=mean(yMat,0)
    yMat=yMat-yMean
    xMeans=mean(xMat,0)
    xVar=var(xMat,0)
    xMat=(xMat-xMeans)/xVar
    m,n=shape(xMat)
    returnMat=zeros((numIt,n))
    ws=zeros((n,1))
    wsTest=ws.copy()
    wsMax=ws.copy()

    #每轮迭代过程
    for i in range(numIt):
        print(ws.T)
        lowesError=inf
        for j in range(n):
            for sign in [-1,1]:
                wsTest=ws.copy()
                wsTest[j]+=eps*sign
                yTest=xMat*wsTest
                rssE=rssError(yMat.A,yTest.A)
                if rssE<lowesError:
                    lowesError=rssE
                    wsMax=wsTest
        ws=wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat

#分析预测误差大小
def rssError(yArr,yHatArr):
    return((yArr-yHatArr)**2).sum()

def plotlasso(returnWeights):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.plot(returnWeights)
    plt.savefig('前向逐步回归系数变化图.png')
    plt.show()
#----------------------------------------------------------------------------


def main():
# #1.---------线性回归---------------------------
#     xArr,yArr=loadDataSet('ex0.txt')
#     ws=standRegres(xArr,yArr)
#     plotScatter(xArr,yArr,ws)
# #---------------------------------------------
# #2.--------局部加权线性回归---------------------
#     xArr,yArr=loadDataSet('ex0.txt')
#     #ws=lwlr(xArr[0],xArr,yArr,0.001)
#     #print(ws)
#     yHat=lwlrTest(xArr,xArr,yArr,0.01)
#     plotScatterlwlr(xArr,yArr,yHat)
# #---------------------------------------------

# #3.---------岭回归------------------------------
#     abX,abY=loadDataSet('abalone.txt')
#     ridgeWeights=ridgeTest(abX,abY)
#     plotRidge(ridgeWeights)
#
# #----------------------------------------------

#4.---------前向逐步回归--------------------------
    xArr,yArr=loadDataSet('abalone.txt')
    returnMat=stageWise(xArr,yArr,0.005,1000)
    plotlasso(returnMat)
    print(returnMat)
#-----------------------------------------------


if __name__=='__main__':
    main()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值