1. 程式人生 > >機器學習實戰第8章預測數值型數據:回歸

機器學習實戰第8章預測數值型數據:回歸

矩陣 向量 from his sca ima 用戶 targe 不可

1.簡單的線性回歸

假定輸入數據存放在矩陣X中,而回歸系數存放在向量W中,則對於給定的數據X1,預測結果將會是

                技術分享圖片

這裏的向量都默認為列向量

現在的問題是手裏有一些x和對應的y數據,怎樣才能找到W呢?一個常用的方法是找到使誤差最小的W,這裏的誤差是指預測y值與真實y值之間的差值,使用該誤差的簡單累加將使得正差值和負差值相互抵消,所以我們采用平方誤差。

平方誤差可以寫做:

                技術分享圖片

用矩陣表示可以寫成

                技術分享圖片

使用上式對w進行求導:

                技術分享圖片

具體可參考https://blog.csdn.net/nomadlx53/article/details/50849941

令上述導數為0,即可得

                技術分享圖片

2. 局部加權線性回歸

  線性回歸的一個問題是有可能出現欠擬合現象,因為它求的是具有小均方誤差的無偏估計。顯而易見,如果模型欠擬合將不能取得好的預測效果。所以有些方法允許在估計中引入一 些偏差,從而降低預測的均方誤差。

  其中的一個方法是局部加權線性回歸(Locally Weighted Linear Regression,LWLR)。在該方法中,我們給待預測點附近的每個點賦予一定的權重。與kNN一樣,這種算法每次預測均需要事先選取出對應的數據子集。該算法解除回歸系數W的形式如下:

                      技術分享圖片

  LWLR使用"核"(與支持向量機中的核類似)來對附近的點賦予更高的權重。核的類型可以自由選擇,最常用的核就是高斯核,高斯核對應的權重如下:

                    技術分享圖片

  其中k需要用戶設定,它決定了對附近的點賦予多大的權重,控制衰減速度

下面是代碼

from numpy import mat,linalg,corrcoef,shape,eye,exp,zeros
import matplotlib.pyplot as plt
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


"""
    函數說明:線性回歸
    ParameterS:
        xArr - x數據集
        yArr - y數據集
    Returns:
        ws  - 回歸系數
"""
def standRegres(xArr, yArr):
    xMat = mat(xArr); yMat = mat(yArr).T
    xTx = xMat.T*xMat
    # linalg.det()計算行列式,若為0,則不可逆
    if linalg.det(xTx) == 0.0:
        print("This matrix is singular, cannot do inverse")
        return
    #回歸系數ws = (X^TX)^-1X^Ty
    ws = xTx.I * (xMat.T * yMat)
    return ws


def plotStandRegres(xMat, yMat, ws):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    xCopy = xMat.copy()
    yHat = xCopy * ws
    # flatten()函數Return a copy of the array collapsed into one dimension.
    # .A將矩陣轉化為數組
    ax.scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
    ax.plot(xCopy[:, 1], yHat,‘r‘)
    plt.show()


"""
    函數說明:局部加權線性回歸
    Parameters:
        testPoint - 測試點,xArr -  x數據集,yArr - y數據集,
        k   - 高斯核的參數,自定義,控制衰減速度
    Returns:
        測試點y值
"""
def lwlr(testPoint, xArr, yArr, k=1.0):
    xMat = mat(xArr)    # m * n
    yMat = mat(yArr).T  # m * 1
    m = shape(xMat)[0]
    weights = mat(eye(m))   #生成對角矩陣,對角線上元素全為1,其他為0
    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))
    return testPoint * ws


"""
    函數說明:局部加權線性回歸測試函數
    Parameters:
        testPoint - 測試x數據集,xArr -  x數據集,yArr - y數據集,
        k - 高斯核的參數,自定義,控制衰減速度
    Returns:
        yHat - 預測y數據集 
"""
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)
    return yHat


def plotLwlr(xMat, yMat):
    plt.rcParams[‘font.sans-serif‘] = [‘SimHei‘]
    plt.rcParams[‘axes.unicode_minus‘] = False
    strInd = xMat[:,1].argsort(0)   #對x進行排序,並返回排序下標
    xSort = xMat[strInd][:,0,:]
    yHat1 = lwlrTest(xArr, xArr, yArr, 1.0)
    yHat2 = lwlrTest(xArr, xArr, yArr, 0.01)
    yHat3 = lwlrTest(xArr, xArr, yArr, 0.003)
    fig, axs = plt.subplots(nrows=3, ncols=1, sharex=False, sharey=False, figsize=(10, 8))
    axs[0].plot(xSort[:, 1], yHat1[strInd], c=‘red‘)
    axs[1].plot(xSort[:, 1], yHat2[strInd], c=‘red‘)
    axs[2].plot(xSort[:, 1], yHat3[strInd], c=‘red‘)
    axs[0].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
    axs[1].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
    axs[2].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
    #設置標題,x軸y軸label
    axs0_title_text = axs[0].set_title(u‘局部加權回歸曲線,k=1.0‘)
    axs1_title_text = axs[1].set_title(u‘局部加權回歸曲線,k=0.01‘)
    axs2_title_text = axs[2].set_title(u‘局部加權回歸曲線,k=0.003‘)
    plt.setp(axs0_title_text, size=8, weight=‘bold‘, color=‘red‘)
    plt.setp(axs1_title_text, size=8, weight=‘bold‘, color=‘red‘)
    plt.setp(axs2_title_text, size=8, weight=‘bold‘, color=‘red‘)
    plt.xlabel(‘X‘)
    plt.ylabel(‘Y‘)
    plt.show()


if __name__ == ‘__main__‘:
    xArr, yArr = loadDataSet(‘ex0.txt‘)
    ws = standRegres(xArr, yArr)
    xMat = mat(xArr)
    yMat = mat(yArr)
    yHat = xMat * ws  # 預測y值
    plotStandRegres(xMat, yMat, ws)
    #計算相關系數
    print(corrcoef(yHat.T, yMat))
    plotLwlr(xMat, yMat)

簡單線性回歸的運行結果:

    技術分享圖片

相關系數:

      技術分享圖片

  

局部加權回歸:

  技術分享圖片

從圖中可以看出在三種k的取值中,k=0.01的結果相對更好一些,k=0.003時會出現過擬合的情況。

局部加權回歸存在一個問題:增加了計算量,每次必須在整個數據集上運行

3.示例:預測鮑魚的年齡

"""
    函數說明:計算誤差
"""
def rssError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
    return ((yArr-yHatArr)**2).sum()

if __name__ == __main__:
    xArr, yArr = regression.loadDataSet(abalone.txt)
    print(訓練集與測試集相同:局部加權線性回歸,核k的大小對預測的影響:)
    yHat01 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 0.1)
    yHat1 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 1)
    yHat10 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 10)
    print(k=0.1時,誤差大小為:,rssError(yArr[0:99], yHat01.T))
    print(k=1時,誤差大小為:,rssError(yArr[0:99], yHat1.T))
    print(k=10.1時,誤差大小為:,rssError(yArr[0:99], yHat10.T))
    print(‘‘)
    print(訓練集與測試集不同:局部加權線性回歸,核k的大小對預測的影響:)
    yHat01 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 0.1)
    yHat1 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 1)
    yHat10 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 10)
    print(k=0.1時,誤差大小為:,rssError(yArr[100:199], yHat01.T))
    print(k=1時,誤差大小為:,rssError(yArr[100:199], yHat1.T))
    print(k=10時,誤差大小為:,rssError(yArr[100:199], yHat10.T))
    print(‘‘)
    print(訓練集與測試集不同:簡單的線性歸:)
    ws = regression.standRegres(xArr[0:99], yArr[0:99]) # 8 * 1
    yHat = xArr[100:199] * ws
    print(rssError(yArr[100:199],yHat.T.A))

  技術分享圖片

  從中可以看出使用訓練數據集做測試集時,k=0.1時的誤差最小,但使用不同訓練集的數據做測試數據集時,k=0.1的誤差最大,說明了可能出現了過擬合的情況,因此在選取k值時應選擇使測試誤差最小的值。同時我們可以看到,當k=1時,局部加權線性回歸和簡單的線性回歸得到的效果差不多。這也表明一點,必須在未知數據上比較效果才能選取到最佳模型。

參考:

《機器學習實戰第8章》

http://cuijiahua.com/blog/2017/11/ml_11_regression_1.html

機器學習實戰第8章預測數值型數據:回歸