Machine Learning---7--regression

1、线性回归

通过一个线性方程去拟合一些数据点。可设直线方程为 y=wx. 其中w称为回归系数。问题是,如何从一堆x和对应的y中确定w?一个常用的方法就是找出使误差最小的w。这里的误差是指预测y值和真实y值之间的差值,我们采用平方误差,写作:

用矩阵还可以写作: ,如果对w求导,得到,令其等于零,解出w为:

注意此处公式包含对矩阵求逆,所以求解时需要先对矩阵是否可逆做出判断。以上求解w的过程也称为“普通最小二乘法”。

Python实现代码如下:

import numpy as np

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
    if np.linalg.det(xTx) == 0.0:#判断行列式是否为0
        print("This matrix is singular, cannot do inverse")
        return
    ws = xTx.I * (xMat.T*yMat)#也可以用NumPy库的函数求解:ws=linalg.solve(xTx,xMat.T*yMatT)
    return ws

if __name__ == "__main__":
    '''线性回归'''
    xArr,yArr=loadDataSet('ex0.txt')
    ws=standRegres(xArr,yArr)
    xMat=np.mat(xArr)
    yMat=np.mat(yArr)
    #预测值
    yHat=xMat*ws
    print(yHat)
    print('-----------------------------')
    
    #计算预测值和真实值得相关性
    corrf=np.corrcoef(yHat.T,yMat)#  求相关系数0.986---相关系数越大,模型越好
    print(corrf)
    
    #绘制数据集散点图和最佳拟合直线图
    #创建图像并绘出原始的数据
    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()

2、局部加权线性回归

局部加权线性回归给待预测点附近的每个点赋予一定的权重,用于解决线性回归可能出现的欠拟合现象。与kNN法类似,这种算法每次预测均需要事先选取出对应的数据子集,然后在这个子集上基于最小均分差来进行普通的回归。该算法解出回归系数的形式如下:

其中w是一个权重矩阵,通常采用核函数来对附近的点赋予权重,最常用的核函数是高斯核,如下:

这样就构建了一个只含对角元素的权重矩阵W并且点x与x(i)越近,w(i,i)将会越大,k值控制衰减速度,且k值越小被选用于训练回归模型的数据集越小。

Python实现代码:

import numpy as np

## 2、局部加权线性回归---用于解决线性回归可能出现的欠拟合现象

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 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):
    '''为数据集中每个点调用lwlr()'''
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

def rssError(yArr,yHatArr):   #返回预测误差
    return((yArr-yHatArr)**2).sum()

if __name__ == "__main__":    
    '''局部加权线性回归'''
    xArr,yArr=loadDataSet('ex0.txt')
    #拟合
    yHat=lwlrTest(xArr,xArr,yArr,0.01)   #改变k的值,当k=1.0时回到线性回归(欠拟合),当k=0.03时过拟合
    #绘图
    xMat=np.mat(xArr)
    yMat=np.mat(yArr)
    srtInd = xMat[:,1].argsort(0)  #数据点排序
    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()
    
    ##预测鲍鱼年龄的误差
    abX,abY=loadDataSet('abalone.txt')
    yHat01=lwlrTest(abX[0:99],abX[0:99],abY[0:99],0.1)
    error1=rssError(abY[0:99],yHat01)
    error2=rssError(abY[100:199],yHat01)  #对于新的训练集效果差
    print(error1)
    print('----------------------------------')
    print(error2)

3、岭回归

如果数据的特征比样本点多(n>m),也就是说输入数据的矩阵x不是满秩矩阵。而非满秩矩阵在求逆时会出错,所以此时不能使用之前的线性回归方法。为解决这个问题,统计学家引入了岭回归的概念。

简单来说,岭回归就是在矩阵xTx上加一个λI从而使得矩阵非奇异,进而能对 xTx+λI 求逆,其中I是一个mxm的单位矩阵。在这种情况下,回归系数的计算公式将变成:

这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能减少不重要的参数,这个技术在统计学中也叫缩减。

Python实现代码:

import numpy as np

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 ridgeRegres(xMat,yMat,lam=0.2):  ##lam默认为0.2
    '''计算岭回归系数'''
    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")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws
    
def ridgeTest(xArr,yArr):
    '''用于在一组lambda上测试结果'''
    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 #取30个不同的lambda调用函数
    wMat = np.zeros((numTestPts,np.shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat,yMat,np.exp(i-10)) #lam以指数级变化
        wMat[i,:]=ws.T
    return wMat

if __name__ == "__main__":
    '''岭回归'''
    abX,abY=loadDataSet('abalone.txt')
    ridgeWeights = ridgeTest(abX,abY)#得到30组回归系数
    #缩减效果图
    import matplotlib.pyplot as plt
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.plot(ridgeWeights)
    plt.show()

4、前向逐步回归

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

Python实现代码:

import numpy as np

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 regularize(xMat):
    '''数据标准化函数'''
    inMat = xMat.copy()
    inMeans = np.mean(inMat,0)
    inVar = np.var(inMat,0)
    inMat = (inMat - inMeans)/inVar
    return inMat
    
def rssError(yArr,yHatArr): 
    '''计算均方误差大小'''
    return ((yArr-yHatArr)**2).sum()

def stageWise(xArr,yArr,eps=0.01,numIt=100):
    '''
    逐步线性回归算法
    eps:表示每次迭代需要调整的步长
    '''
    xMat = np.mat(xArr); yMat=np.mat(yArr).T
    yMean = np.mean(yMat,0)
    yMat = yMat - yMean
    xMat = regularize(xMat)
    m,n=np.shape(xMat)
    returnMat = np.zeros((numIt,n)) #testing code remove
    #为了实现贪心算法建立ws的两份副本
    ws =np. zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy()
    for i in range(numIt):
        print(ws.T)
        lowestError = np.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 < lowestError:
                    lowestError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat

if __name__ == "__main__":
    '''前向逐步线性回归'''    
    abX,abY=loadDataSet('abalone.txt')
    stageWise(abX,abY,0.01,200)






猜你喜欢

转载自blog.csdn.net/qq_38096703/article/details/77853718