天天看點

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

1.什麼是線性回歸?

線性回歸是試圖在一堆資料中訓練得到自變量x和因變量y中一組線性關系,如 y = w x + b y=wx+b y=wx+b。例如把人腳底闆長度作為自變量,身高作為因變量,那麼在這兩種資料之間就可以做一個簡單線性回歸,可以得到腳底闆長度和身高的關系式。

維基百科:線性回歸

在統計學中,線性回歸是利用稱為線性回歸方程的最小二乘函數對一個或多個自變量和因變量之間關系進行模組化的一種回歸分析。

周志華:機器學習

基于均方誤差最小化來進行模型求解的方法稱為“最小二乘法”,線性回歸中最小二乘法就是試圖找到一條直線,使所有樣本到直線上的歐氏距離之和最小。

2. 線性回歸的目标函數

要想求得這組線性關系,即求得相應的回歸系數的值。那麼先講解一下線性回歸的目标函數。

假設一堆資料中因變量為y,自變量為 x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1​,x2​,...,xn​,對其進行線性回歸,求得結果會如下所示:

y = w 0 + w 1 x 1 + w 2 x 2 + . . . + w n x n = ∑ i = 0 n w i x i = w T x y=w_0+w_1x_1+w_2x_2+...+w_nx_n=\sum_{i=0}^nw_ix_i=w^Tx y=w0​+w1​x1​+w2​x2​+...+wn​xn​=i=0∑n​wi​xi​=wTx

其中w0是x0=1的系數,表示為全局偏移量,在平面直線中的具體意義為截距,也作為自變量的一個次元,其中w就是我們需要求得的。那麼怎麼去求得這個w呢?假設一共有m個樣本,對于第i個資料,有

y ( i ) = w T x ( i ) + ξ ( i ) y^{(i)}=w^Tx^{(i)}+\xi^{(i)} y(i)=wTx(i)+ξ(i)

對于一個樣本來說, y ( i ) − w T x ( i ) y^{(i)}-w^Tx^{(i)} y(i)−wTx(i)為一個樣本存在的誤差。顯然求得需要的w的方法,就是找出使誤差最小的w,然而使用這個誤差的簡單累加将使得正內插補點和複內插補點抵消,是以我們采用均方誤差,那麼對于全部的m個樣本來說,總誤差為

J ( w ) = ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 J(w)=\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2 J(w)=i=1∑m​(y(i)−wTx(i))2

均方誤差是回歸任務中最常用的性能度量,有非常好的幾何意義,它對應了常用的歐幾裡得距離或簡稱“歐氏距離”

顯然我們需要這個總誤差的值為最小,是以取目标函數為

J ( w ) = ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 J(w)=\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2 J(w)=i=1∑m​(y(i)−wTx(i))2

求這個目标函數最小值時的w,就是我們需要的w了。

3. 求目标函數得回歸系數

3.1 梯度下降算法

對于求最小值的問題,我們能想到的第一個應該是梯度下降算法。在實驗過程中發現,在對上述的目标函數進行梯度下降時,需要把步長設定的很小很小才行,為此我們先将目标函數改為如下形式

J ( w ) = 1 2 m ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 J(w)=\frac{1}{2m}\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2 J(w)=2m1​i=1∑m​(y(i)−wTx(i))2

之後我們使用梯度下降算法來求這個目标函數的最小值。該目标函數的梯度為

∇ J ( w ) = ( ∂ J ( w ) ∂ w 1 , ∂ J ( w ) ∂ w 2 , . . . , ∂ J ( w ) ∂ w n + 1 ) \nabla J(w) = (\frac{\partial J(w)}{\partial w_1},\frac{\partial J(w)}{\partial w_2},...,\frac{\partial J(w)}{\partial w_{n+1}}) ∇J(w)=(∂w1​∂J(w)​,∂w2​∂J(w)​,...,∂wn+1​∂J(w)​)

∂ J ( w ) ∂ w j = ∂ 1 2 m ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 ∂ w j = 1 2 m ∑ i = 1 m ∂ ( y ( i ) − w T x ( i ) ) 2 ∂ w j = 1 m ∑ i = 1 m ( w T x ( i ) − y ( i ) ) . x j i \begin{aligned} \frac{\partial J(w)}{\partial w_j} &= \frac{\partial {\frac{1}{2m}\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2}}{\partial w_j}\\ &=\frac{1}{2m}\sum_{i=1}^m\frac{\partial (y^{(i)}-w^Tx^{(i)})^2}{\partial w_j}\\ &=\frac{1}{m}\sum_{i=1}^m(w^Tx^{(i)}-y^{(i)}).x_j^i \end{aligned} ∂wj​∂J(w)​​=∂wj​∂2m1​∑i=1m​(y(i)−wTx(i))2​=2m1​i=1∑m​∂wj​∂(y(i)−wTx(i))2​=m1​i=1∑m​(wTx(i)−y(i)).xji​​

是以使用梯度算法疊代的公式為

w j = w j − α ∂ J ( w ) ∂ w j = w j − α m ∑ i = 1 m ( w T x ( i ) − y ( i ) ) . x j i \begin{aligned} w_j &= w_j-\alpha\frac{\partial J(w)}{\partial w_j}\\ &=w_j-\frac{\alpha}{m}\sum_{i=1}^m(w^Tx^{(i)}-y^{(i)}).x_j^i \end{aligned} wj​​=wj​−α∂wj​∂J(w)​=wj​−mα​i=1∑m​(wTx(i)−y(i)).xji​​

然而對于疊代過程中使用的訓練集數量不同,會有不同細分的梯度下降算法,但是都是梯度下降算法,核心沒有變。

  • 批量梯度下降算法

    使用所有的資料集,存在的問題是每次下降都要對整個資料集進行周遊運算,當資料集很大時,他的計算機會出現溢出,或者計算時間非常長。然而随機梯度下降就可以解決這些問題。

  • 随機梯度下降算法

    每次疊代使用的是一組資料。然而随機梯度下降算法由于每次隻是用了一組資料,因為他受噪聲/離群點/異常值的影響非常大,由此有了一種折中的方法,那就是小批量梯度下降。

  • 小批量梯度下降算法

    每次疊代時使用一批資料,這批資料可以自行選擇也可以随機産生,大小也可自由定,越大就越接近批量梯度下降,越小就越接近随機梯度下降。

下面是上述三種算法的Python代碼實作,可以參考一下:

'''
批量梯度下降算法
'''
def BGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)

    for k in range(times):
        # 一次疊代
        for j in range(len(theta)):
            sum = 0.0
            # 進行求和
            for xi, yi in zip(xArr, yArr):
                sum += ((theta * xi).sum() - yi) * xi[j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m  # 不除以m的話,得把步長設定的很小很小

    return theta


'''
随機梯度下降算法
'''
def SGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)

    for k in range(times * 10):
        t = random.randint(0, m - 1)
        # 一次疊代
        for j in range(len(theta)):
            sum = ((theta * xArr[t]).sum() - yArr[t]) * xArr[t][j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m
    return theta


'''
小批量梯度下降算法
'''
def MBGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)
    n = 5  # 小批量資料的數量

    for k in range(times):
        # 随機産生小批量的資料
        train_set = []
        for t in range(n):
            train_set.append(random.randint(0, m - 1))
        # 一次疊代
        for j in range(len(theta)):
            sum = 0.0
            for i in train_set:
                sum += ((theta * xArr[i]).sum() - yArr[i]) * xArr[i][j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m

    return theta
           

3.2 矩陣求導

針對這個最小值的求法我們還可以使用的矩陣的方法,上述的目标函數

J ( w ) = ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 J(w)=\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2 J(w)=i=1∑m​(y(i)−wTx(i))2

可以用矩陣表示為,

J ( w ) = ∑ i = 1 m ( y ( i ) − w T x ( i ) ) 2 = ( y − X w ) T ( y − X w ) J(w)=\sum_{i=1}^{m}(y^{(i)}-w^Tx^{(i)})^2=(y-Xw)^T(y-Xw) J(w)=i=1∑m​(y(i)−wTx(i))2=(y−Xw)T(y−Xw)

其中X表示m個n維樣本,每一行表示一個樣本,即X為mxn階矩陣。之後求向量w的導數

J ′ ( w ) = 2 X T ( X w − y ) J'(w)=2X^T(Xw-y) J′(w)=2XT(Xw−y)

令上式為0,求得

w = ( X T X ) − 1 X T y w = (X^TX)^{-1}X^Ty w=(XTX)−1XTy

這個w就是我們需要的回歸系數。但是需要注意的是,在求該式的時候涉及到了矩陣逆的計算,是以這個方程隻能在逆矩陣存在的時候适用。

矩陣求導方式的核心代碼實作

'''
矩陣的方法求參數值
'''
def mat(xArr, yArr):
    xMat = np.mat(xArr)  # x矩陣
    xMatT = xMat.T  # x的轉置矩陣
    yMat = np.mat(yArr).T  # y矩陣
    xTx = xMatT * xMat
    if (np.linalg.det(xTx) != 0):
        theta = xTx.I * xMatT * yMat
        return theta
    return None
           

4. 簡單線性回歸的Python實作

下面我們模拟出分布在某個函數周圍的資料,然後使用上述四種方法進行線性回歸,全部代碼如下

import numpy as np
import math
import random
import matplotlib.pyplot as plt


'''
批量梯度下降算法
'''
def BGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)

    for k in range(times):
        # 一次疊代
        for j in range(len(theta)):
            sum = 0.0
            # 進行求和
            for xi, yi in zip(xArr, yArr):
                sum += ((theta * xi).sum() - yi) * xi[j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m  # 不除以m的話,得把步長設定的很小很小

    return theta


'''
随機梯度下降算法
'''
def SGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)

    for k in range(times * 10):
        t = random.randint(0, m - 1)
        # 一次疊代
        for j in range(len(theta)):
            sum = ((theta * xArr[t]).sum() - yArr[t]) * xArr[t][j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m
    return theta


'''
小批量梯度下降算法
'''
def MBGD(xArr, yArr, alpha, theta, times):
    m = len(xArr)
    n = 5  # 小批量資料的數量

    for k in range(times):
        # 随機産生小批量的資料
        trainSet = []
        for t in range(n):
            trainSet.append(random.randint(0, m - 1))
        # 一次疊代
        for j in range(len(theta)):
            sum = 0.0
            for i in trainSet:
                sum += ((theta * xArr[i]).sum() - yArr[i]) * xArr[i][j]
            # 更新
            theta[j] = theta[j] - (alpha * sum) / m

    return theta


'''
矩陣的方法求參數值
'''
def mat(xArr, yArr):
    xMat = np.mat(xArr)  # x矩陣
    xMatT = xMat.T  # x的轉置矩陣
    yMat = np.mat(yArr).T  # y矩陣
    xTx = xMatT * xMat
    if (np.linalg.det(xTx) != 0):
        theta = xTx.I * xMatT * yMat
        return theta
    return None


'''
畫圖
'''
def draw_line(xArr, theta):
    y = []
    for i in xArr:
        y.append((theta * i).sum())
    plt.plot(xArr[:, 1], np.array(y), 'r', lw=2)


def main():
    x = np.arange(0, 25, 0.5)
    xArr = []
    yArr = []
    # 産生用于訓練的資料
    for xi in x:
        xArr.append([1, xi])
        yArr.append(0.5 * xi + 3 + random.uniform(0, 1) * math.sin(xi))
    xArr = np.array(xArr)
    yArr = np.array(yArr)

    alpha = 0.005  # 步長
    theta = np.array([0.0, 0.0])  # 回歸系數
    times = 10000  # 疊代次數
    theta_re = BGD(xArr, yArr, alpha, theta, times)
    print("批量梯度下降算法下求的theta值 ", theta_re)
    print("批量梯度下降算法求得相關系數為\n",  # 計算相關系數
          np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:,0]))
    draw_line(xArr, theta_re)

    theta_re = SGD(xArr, yArr, alpha, theta, times)
    print("随機梯度下降算法下求的theta值", theta_re)
    print("随機梯度下降算法求得相關系數為\n",  # 計算相關系數
          np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:, 0]))
    draw_line(xArr, theta_re)

    theta_re = MBGD(xArr, yArr, alpha, theta, times)
    print("小批量梯度下降算法下求的theta值", theta_re)
    print("小批量梯度下降算法求得相關系數為\n",
          np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:, 0]))
    draw_line(xArr, theta_re)

    theta_re = mat(xArr, yArr)
    print("矩陣求逆法求得的theta值", np.array(theta_re)[:, 0])
    print("小批量梯度下降算法求得相關系數為\n",
          np.corrcoef(yArr, np.array(np.mat(xArr) * theta_re)[:, 0]))
    draw_line(xArr, np.array(theta_re)[:, 0])

    plt.scatter(x, yArr, 60)
    plt.show()


if __name__ == "__main__":
    main()
           
上述的梯度下降算法中,沒有加上對函數值變換很小時的判斷

控制台的輸出結果如下所示

批量梯度下降算法下求的theta值  [3.15890008 0.48804966]
批量梯度下降算法求得相關系數為
 [[1.         0.99426138]
 [0.99426138 1.        ]]
随機梯度下降算法下求的theta值 [3.15560184 0.49059031]
随機梯度下降算法求得相關系數為
 [[1.         0.99426138]
 [0.99426138 1.        ]]
小批量梯度下降算法下求的theta值 [3.16014486 0.48668596]
小批量梯度下降算法求得相關系數為
 [[1.         0.99426138]
 [0.99426138 1.        ]]
矩陣求逆法求得的theta值 [3.15890797 0.48804918]
小批量梯度下降算法求得相關系數為
 [[1.         0.99426138]
 [0.99426138 1.        ]]
           
  • 可以通過相關系數來判斷預測值和真實值之間的比對程度,以此來比較效果好壞。
  • Numpy庫提供了相關系數的計算方法

    corrcoef()

    ,傳回的矩陣包含所有兩兩組合的相關系數。

批量梯度下降算法的圖形效果如下:

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

随機梯度下降算法的效果如下

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

小批量效果如下

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

矩陣求逆的效果如下

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

5. 局部權重線性回歸

線性回歸的一個問題是很可能出現欠拟合的現象,因為它求的是具有最小均方誤差的無偏估計。然而有時候模型會出現欠拟合的情況,那麼這種情況下将不能取得很好的預測效果。是以有些方法允許在估計中引入一些偏差,來降低預測的均方誤差。其中一個方法就是局部權重線性回歸(LWLR)。

依舊使用前面使用過的那個目标函數,隻是現在是進行權重之後的,如下所示

J ( θ ) = ∑ i = 1 m w ( i ) ( y ( i ) − θ T x ( i ) ) 2 J(\theta)=\sum_{i=1}^{m}w^{(i)}(y^{(i)}-\theta^Tx^{(i)})^2 J(θ)=i=1∑m​w(i)(y(i)−θTx(i))2

其中w(i)是權重,根據要預測的點與資料集中的點的距離來為資料集中的點賦權值。某點離要預測的點越遠,其權重越小,否則越大。LWLR使用“核”來對附近的點賦予更高的權重,最常用的核實高斯核,高斯核對應的權重如下:

w ( i ) = e x p ( ∣ x ( i ) − x ∣ − 2 k 2 ) w^{(i)}=exp(\frac{|x^{(i)}-x|}{-2k^2}) w(i)=exp(−2k2∣x(i)−x∣​)

上述公式中包含一個需要使用者指定的參數k,它決定了對附近的點賦予多大的權重,這也是使用LWLR時唯一需要考慮的參數。然後對上式進行求解,解得回歸系數如下

θ = ( X T W X ) − 1 X T W y \theta = (X^TWX)^{-1}X^TWy θ=(XTWX)−1XTWy

W​是權重矩陣,其中

w ( i , i ) = w ( i ) w(i,i) = w^{(i)} w(i,i)=w(i)

根據上述公式,編寫相應的Python代碼,通過改變K值來調節回歸效果,代碼如下

import numpy as np
import random
import matplotlib.pyplot as plt
import math

'''
針對一個點的局部線性回歸
'''
def lwlr(testPoint, xArr, yArr, k=1.0):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weight = np.mat(np.eye(m))  # 對角都是1的矩陣
    for i in range(m):
        diffMat = testPoint - xMat[i, :]
        weight[i, i] = np.exp((diffMat * diffMat.T) / (-2 * k ** 2))
    xTx = xMat.T * weight * xMat
    if np.linalg.det(xTx) != 0:
        theta = xTx.I * xMat.T * weight * yMat
        return theta
    return None


def lwlrAll(testArr, xArr, yArr, k=1.0):
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        thetaRe = lwlr(testArr[i], xArr, yArr, k)
        yHat[i] = testArr[i] * thetaRe
    return yHat


def main():
    # 産生用于訓練的資料
    x = np.arange(0, 25, 0.5)
    xArr = []
    yArr = []
    for xi in x:
        xArr.append([1, xi])
        yArr.append(0.5 * xi + 3 + random.uniform(0, 1) * math.sin(xi))
    xArr = np.array(xArr)
    yArr = np.array(yArr)

    # 對所有樣本依次進行局部線性回歸,并畫圖
    plt.figure(1)
    yHat = lwlrAll(xArr, xArr, yArr, 1.0)
    plt.scatter(xArr[:, 1], yArr, 60)
    plt.plot(xArr[:, 1], yHat, 'r', lw=2)

    plt.figure(2)
    yHat = lwlrAll(xArr, xArr, yArr, 0.3)
    plt.scatter(xArr[:, 1], yArr, 60)
    plt.plot(xArr[:, 1], yHat, 'r', lw=2)

    plt.figure(3)
    yHat = lwlrAll(xArr, xArr, yArr, 0.1)
    plt.scatter(xArr[:, 1], yArr, 60)
    plt.plot(xArr[:, 1], yHat, 'r', lw=2)

    plt.show()


if __name__ == "__main__":
    main()
           

上述代碼的效果如下,第一張圖是K=1.0的,拟合的效果較好;第二張圖是K=0.3的;第三張圖是K=0.1,考慮太多噪聲,有點過拟合了。

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)
機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)
機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

最後說一下局部線性回歸存在的問題,局部線性回歸增加一定的計算量,因為它對每個點做預測時都必須使用整個資料集。從上述圖中K=0.1的情況中可以看出,大多資料點的權重都接近零,如果避免這些計算将可以減少程式運作時間,進而緩解計算機量增加帶來的問題。

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

這個示例是機器學習實戰這本書上的一個示例,将局部線性回歸知識用于真實資料。使用的是來自UCI資料集合的資料,資料集大概情況如下(資料集位址見文末)

1	0.455	0.365	0.095	0.514	0.2245	0.101	0.15	15
1	0.35	0.265	0.09	0.2255	0.0995	0.0485	0.07	7
-1	0.53	0.42	0.135	0.677	0.2565	0.1415	0.21	9
1	0.44	0.365	0.125	0.516	0.2155	0.114	0.155	10
0	0.33	0.255	0.08	0.205	0.0895	0.0395	0.055	7
0	0.425	0.3		0.095	0.3515	0.141	0.0775	0.12	8
-1	0.53	0.415	0.15	0.7775	0.237	0.1415	0.33	20
-1	0.545	0.425	0.125	0.768	0.294	0.1495	0.26	16
1	0.475	0.37	0.125	0.5095	0.2165	0.1125	0.165	9
-1	0.55	0.44	0.15	0.8945	0.3145	0.151	0.32	19
-1	0.525	0.38	0.14	0.6065	0.194	0.1475	0.21	14
1	0.43	0.35	0.11	0.406	0.1675	0.081	0.135	10
1	0.49	0.38	0.135	0.5415	0.2175	0.095	0.19	11
-1	0.535	0.405	0.145	0.6845	0.2725	0.171	0.205	10
-1	0.47	0.355	0.1		0.4755	0.1675	0.0805	0.185	10
1	0.5		0.4		0.13	0.6645	0.258	0.133	0.24	12
0	0.355	0.28	0.085	0.2905	0.095	0.0395	0.115	7
-1	0.44	0.34	0.1		0.451	0.188	0.087	0.13	10
1	0.365	0.295	0.08	0.2555	0.097	0.043	0.1		7
           

從資料集可以看到,資料集是多元的,最後一列代表鮑魚的真實年齡,前面幾列的資料是一些鮑魚的特征,例如鮑魚殼的層數等,基于的推論是鮑魚的真實年齡可由鮑魚殼的層數等鮑魚的特征推算而出。下面我們不對資料進行處理,直接測試局部權重回歸的效果:

import numpy as np


def loadDataSet(filePath):
    f = open(filePath)
    numFeat = len(f.readline().split("\t")) - 1  # 擷取一行特征的數量
    dataList = []
    labelList = []
    f.seek(0)  # 檔案指針回到初始位置
    for line in f.readlines():
        lineArr = []
        curLine = line.strip().split("\t")  # strip去掉\n
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataList.append(lineArr)
        labelList.append(float(curLine[-1]))
    return dataList, labelList


def lwlr(testPoint, xArr, yArr, k=1.0):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weight = np.mat(np.eye(m))
    for i in range(m):
        diffMat = testPoint - xMat[i, :]
        weight[i, i] = np.exp((diffMat * diffMat.T) / (-2.0 * k ** 2))

    xTx = xMat.T * (weight * xMat)

    if np.linalg.det(xTx) != 0.0:
        theta = xTx.I * (xMat.T * (weight * yMat))
        return testPoint * theta
    return None


def lwlrAll(testArr, xArr, yArr, k=1.0):
    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 standRegres(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) != 0.0:
        theta = xTx.I * (xMat.T * yMat)
        return theta
    return None


def rssError(yArr, yHatArr):
    return ((yArr - yHatArr) ** 2).sum()


if __name__ == '__main__':
    abaloneX, abaloneY = loadDataSet("abalone.txt")

    yHat01 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 0.1)
    yHat1 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 1)
    yHat10 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 10)
    print("k=0.1時,訓練集上的誤差為:", rssError(abaloneY[0:99], yHat01))
    print("k=1時,訓練集上的誤差為:", rssError(abaloneY[0:99], yHat1))
    print("k=10時,訓練集上的誤差為:", rssError(abaloneY[0:99], yHat10))

    yHat01 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 0.1)
    yHat1 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 1)
    yHat10 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 10)
    print("k=0.1時,測試集上的誤差為:", rssError(abaloneY[100:199], yHat01))
    print("k=1時,測試集上的誤差為:", rssError(abaloneY[100:199], yHat1))
    print("k=10時,測試集上的誤差為:", rssError(abaloneY[100:199], yHat10))

    theta = standRegres(abaloneX[0:99],abaloneY[0:99])
    yHat = np.mat(abaloneX[100:199])*theta
    print("簡單線性回歸時的誤差為:", rssError(abaloneY[100:199], yHat.T.A))
           

輸出結果如下:

k=0.1時,訓練集上的誤差為: 56.78868743050092
k=1時,訓練集上的誤差為: 429.89056187038
k=10時,訓練集上的誤差為: 549.1181708827924
k=0.1時,測試集上的誤差為: 57913.51550155911
k=1時,測試集上的誤差為: 573.5261441895982
k=10時,測試集上的誤差為: 517.5711905381903
簡單線性回歸時的誤差為: 518.6363153245542
           

從輸出結果可以看出,當核k=10的時候,訓練集上的誤差是最大的,但是測試集上的誤差是最小的,同時它效果和簡單線性回歸的效果類似。是以在所有資料集上都使用最小的核的話,将會造成過拟合,在新資料上不一定能達到最好的預測效果。

注意:

1.在局部權重線性回歸中,過小的核可能導緻過拟合現象,即在訓練集上表現良好,但在測試集上表現就不行了;

2.訓練的模型要在測試集上比較他們的效果,而不是訓練集;

7.如何用線性回歸模型拟合非線性關系

線性模型也可以拟合自變量和因變量之間的非線性關系,隻是需要對樣本資料進行修改。比如有一些樣本,隻有一個特征,我們把特征和結果作圖以後發現,可能是這個樣子的:

機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)

從樣本特征和結果關系走勢來看,這不是一個直線,看起來挺像二階曲線的,那麼我們可以把一個特征“變成”兩個,如

設 X = ( x 1 , x 2 ) ( 其 中 x 1 = x 2 ; x 2 = x ) , 有 : f ( x 1 , x 2 ) = a + b 1 x 2 + b 2 x = a + b 1 x 1 + b 2 x 2 設 X=(x_1,x_2)(其中 x_1=x^2;x_2=x),有:\\ f(x_1,x_2)=a+b_1x^2+b_2x=a+b_1x_1+b_2x_2 設X=(x1​,x2​)(其中x1​=x2;x2​=x),有:f(x1​,x2​)=a+b1​x2+b2​x=a+b1​x1​+b2​x2​

那麼在添加“新的特征”之後的樣本集上去訓練這個函數

f ( x 1 , x 2 ) = a + b 1 x 1 + b 2 x 2 f(x_1,x_2)=a+b_1x_1+b_2x_2 f(x1​,x2​)=a+b1​x1​+b2​x2​

那麼得到回歸系數之後代回函數

f ( x ) = a + b 1 x 2 + b 2 x f(x)=a+b_1x^2+b_2x f(x)=a+b1​x2+b2​x

那麼就相當于拟合了一個二階多項式了。這種操作以此類推都可以,比如三階、四階、對數都行。

  1. 預測鮑魚的年齡的資料集位址:https://github.com/xiaoheidev/MachineLearningInActionSourceCode/blob/master/Ch08/abalone.txt

參考内容

  1. 機器學習,周志華
  2. 機器學習實戰,[美]Peter Harrington
  3. CSDN_線性回歸及其Python實作(最大似然法)
  4. CSDN_Python實作批量梯度下降 随機梯度下降 小批量梯度下降 代碼
  5. CSDN_【機器學習】局部權重線性回歸
機器學習系列 | 線性回歸模型(簡單線性回歸、局部線性回歸、非線性關系)
歡迎關注微信公衆号【一口程式鍋】,一口想煮點技術的鍋。

繼續閱讀