《機器學習實戰》-線性迴歸

線性迴歸

本章內容算法

  • 線性迴歸
  • 局部加權線性迴歸
  • 嶺迴歸和逐步線性迴歸
  • 預測鮑魚年齡和樂高玩具價格

前面的章節給你們介紹了監督學習的分類部分,接下來幾章將會帶領同窗們翱翔浩瀚的迴歸海洋,注意此迴歸不是 Logistic 迴歸(Logistic 迴歸之因此取名爲這是由於歷史遺留問題)。具體是什麼,那就開始讓咱們來揭祕吧!
注意: 分類的目標變量是標稱型數據;迴歸的目標變量是連續性數據。api

用線性迴歸找到最佳擬合直線

  • 線性迴歸的優缺點:
    ​ 優勢:結果易於理解,計算上不復雜
    ​ 缺點:對非線性的數據擬合很差
    ​ 適用數據類型:數值型和標稱型數據
  • 迴歸的目的:預測數值型的目標值
  • 預測汽車功率大小的計算公式:
    功率 = 0.0015 * 耗油量 + 0.99 * 百米加速時長 (純屬虛構,請勿模仿)
  • 迴歸方程:上述計算公式即迴歸方程
  • 迴歸係數:上述計算公式中的0.0015和0.99
  • 預測值:給定全部待輸入的特徵值乘以對應的迴歸係數的總和
  • 非線性迴歸:輸出爲輸入的乘積,例:功率 = 0.0015 * 耗油量 * 百米加速時長
  • 迴歸的通常方法:
    1. 收集數據:採用任意方法收集數據
    2. 準備數據:迴歸須要數值型數據,標稱型數據將被轉成數值型數據
    3. 分析數據:可視化數據,採用縮減法求得新迴歸係數後繪圖再與上一張圖比較
    4. 訓練算法:找到合適的迴歸係數
    5. 測試算法:使用 R^2^或者預測值和數據的擬合度,來分析模型的效果
    6. 使用算法:使用迴歸預測連續性數據的類別標籤
  • 矩陣x:輸入的全部數據
  • 向量 w:與數據對應的迴歸係數
  • 預測結果 Y~1~:\(Y_1={X^T}_1w\)
  • 平方偏差:\(\sum_{i=1}^m(y_i-{x^T}_iw)^2\)
  • 矩陣表示平方偏差:\((y-Xw)^T(y-Xw)\)
  • 平方偏差對 w 求導:\(X^T(Y-Xw)\)
  • 平方偏差對 w 求導等於零得:\(\hat{w}=(X^TX)-1X^Ty\)

  • w 上方的標記含義:當前能夠估計出 w 的最優解,即 w 的一個最佳估計
  • 上述公式包含\((X^TX)^{-1}\),即該方程中的 X 必須存在逆矩陣
    注意:不要糾結於公式,這不會影響你學習機器學習

程序8-1 標準迴歸函數和數據導入函數

# coding: 'utf-8'
import os
import numpy as np
import matplotlib.pyplot as plt
from path_settings import machine_learning_PATH

data_set_path = os.path.join(machine_learning_PATH, '第八章/data-set')
ex0_path = os.path.join(data_set_path, 'ex0.txt')
ex1_path = os.path.join(data_set_path, 'ex1.txt')
abalone_path = os.path.join(data_set_path, 'abalone.txt')


def load_data_set(filename):
    # 文本第一行值全爲0的解釋:簡單說是由於兩個矩陣相乘一個矩陣的行和另外一個矩陣的列得相等,具體可查資料
    num_feat = len(open(filename).readline().split('\t')) - 1

    data_mat = []
    label_mat = []

    fr = open(filename)
    for line in fr.readlines():
        line_arr = []
        cur_line = line.strip().split('\t')
        for i in range(num_feat):
            line_arr.append(float(cur_line[i]))
        data_mat.append(line_arr)
        label_mat.append(float(cur_line[-1]))

    return data_mat, label_mat


def stand_regres(x_arr, y_arr):
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr)
    x_tx = x_mat.T * x_mat

    # 判斷矩陣是否爲奇異矩陣,即矩陣是否有逆矩陣
    if np.linalg.det(x_tx) == 0:
        print("奇異矩陣沒有逆矩陣")
        return

    ws = x_tx.I * (x_mat.T * y_mat.T)

    # 求解未知矩陣
    # ws = np.linalg.solve(x_tx,x_mat.T*y_mat.T)

    return x_mat, y_mat, ws


def test_stand_regres():
    x_arr, y_arr = load_data_set(ex0_path)
    _, _, ws = stand_regres(x_arr, y_arr)
    print(ws)


if __name__ == '__main__':
    test_stand_regres()

程序8-2 基於程序8-1繪圖

def plot_stand_regres(x_mat, y_mat, ws):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x_mat[:, 1].flatten().A[0], y_mat.T[:, 0].flatten().A[0])
    x_copy = x_mat.copy()
    x_copy.sort(0)
    y_hat = x_copy * ws
    ax.plot(x_copy[:, 1], y_hat)
    plt.show()


def test_plot_stand_regres():
    x_arr, y_arr = load_data_set(ex0_path)
    x_mat, y_mat, ws = stand_regres(x_arr, y_arr)
    plot_stand_regres(x_mat, y_mat, ws)

    # 判斷擬合效果
    print(np.corrcoef((x_mat * ws).T, y_mat))
    '''
        [[1.         0.98647356]
        [0.98647356 1.        ]]
    '''


if __name__ == '__main__':
    # test_stand_regres()
    test_plot_stand_regres()

圖片8-1 ex0的數據集和它的最佳擬合直線

局部加權線性迴歸

  • 局部加權線性迴歸:給待預測點附近的每一個點賦予必定的權重
  • 局部加權線性迴歸求迴歸係數公式:\(\hat{w}=(X^TWX)^{-1}X^TWy\)
    app

  • W:給每一個數據點賦予權重的矩陣
  • LWLR使用「核」(相似於支持向量機中的核)來對附近的點賦予更高的權重。
  • 最經常使用的核——高斯核:\(w(i,i)=exp\left({\frac{|x^{(i)}-x|}{-2k^2}}\right)\)
    機器學習

  • 點 x 與 x(i)越近,w(i,i)將會越大,參數 k 決定了對附近的點賦予多大的權重。函數

圖片8-2 參數k與權重的關係

  • 假定咱們正預測的點是 x=0.5,最上面的是原始數據集,第二個圖顯示了當 k=0.5 時,大部分數據都用於訓練迴歸模型;最下面的圖顯示當 k=0.01 時,僅有不多的局部點被用於訓練迴歸模型。

程序8-3 局部加權線性迴歸函數

def lwlr(test_point, x_arr, y_arr, k=1):
    """給樣本點增長權重,參數 k 控制衰減的速度"""
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr)

    m = np.shape(x_mat)[0]

    # 建立對角權重矩陣。該矩陣對角線元素全爲1,其他元素全爲0
    weights = np.mat(np.eye(m))

    for j in range(m):
        diff_mat = test_point - x_mat[j, :]
        weights[j, j] = np.exp(diff_mat * diff_mat.T / (-2 * k ** 2))

    x_tx = x_mat.T * (weights * x_mat)

    if np.linalg.det(x_tx) == 0:
        print("奇異矩陣沒有逆矩陣")
        return

    ws = x_tx.I * (x_mat.T * (weights * y_mat.T))

    return test_point * ws


def lwlr_test(test_arr, x_arr, y_arr, k=1):
    """使數據集中每一個點調用 lwlr 方法"""
    m = np.shape(test_arr)[0]

    y_hat = np.zeros(m)

    for i in range(m):
        y_hat[i] = lwlr(test_arr[i], x_arr, y_arr, k)

    return y_hat


def test_lwlr_test():
    x_arr, y_arr = load_data_set(ex0_path)
    y_hat = lwlr_test(x_arr, x_arr, y_arr, 0.003)
    print(y_hat)


def plot_lwlr(x_sort, y_hat, str_ind, x_mat, y_mat):
    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.plot(x_sort[:, 1], y_hat[str_ind])

    ax.scatter(x_mat[:, 1].flatten().A[0], y_mat.T[:, 0].flatten().A[0], s=2, c='red')

    plt.show()


def test_plot_lwlr():
    x_arr, y_arr = load_data_set(ex0_path)
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr)
    y_hat = lwlr_test(x_arr, x_arr, y_arr, 0.01)
    str_ind = x_mat[:, 1].argsort(0)
    x_sort = x_mat[str_ind][:, 0, :]

    plot_lwlr(x_sort, y_hat, str_ind, x_mat, y_mat)


if __name__ == '__main__':
    # test_stand_regres()
    # test_plot_stand_regres()
    # test_lwlr_test()
    test_plot_lwlr()

圖片8-3 局部加權線性迴歸結果

示例:預測鮑魚的年齡

縮減係數來「理解」數據

嶺迴歸

前向逐步迴歸

權衡誤差與方差

示例:預測樂高玩具套裝的價格

收集數據:使用 Google 購物的 API

訓練算法:創建模型

本章小結

線性迴歸和局部加權線性迴歸

​ 因爲看完《機器學習實戰》第八章中的局部加權線性迴歸後,敲完代碼以後只是知道它是這樣的,但不是很清楚內在的緣由。書中並無對其作過多解釋,百度也找不到一篇很好的文章來解釋 線性迴歸和局部加權線性迴歸 二者之間的區別。索性寫一寫本身對 線性迴歸和局部加權線性迴歸 的見解與感悟。也許仍是不那麼準確,但必定是清晰易懂的。學習


​ 其中的平方偏差是咱們的在 x=x~i~ 上預測值與實際值的差值平方,而咱們須要作的任務就是找到一個最合適的 w 使得該差值平方最小。測試


​ 再來講說咱們的局部加權線性迴歸(LWLR),它只是在線性迴歸的基礎上加了一個權重,而LWLR一般使用「核」(相似於自持向量機中的核)來對附近的點賦予更高的權重。所以它的公式變成:google

\(\sum_{i=1}^mW_i(y_i-x^T_iw)^2\)
spa

注意:W~i~ 是賦予 x~i~ 權重的矩陣,也能夠是向量。

​ 通常咱們的 W~i~ 最經常使用的核是高斯核:\(w(i,i)=exp\left({\frac{|x^{(i)}-x|}{-2k^2}}\right)\)

注意:高斯核中的 x 爲新預測樣本的特徵數據即新的 x,它同 w 也是一個向量,參數 k 控制了權值變化的速率。


​ 以上介紹了局部加權線性迴歸的理論,如今經過圖像咱們再來形象化的解釋局部加權線性迴歸。首先看看不一樣 k 下的參數 k 與權重的關係:

  • 基於上圖咱們能發現兩個規律:
    • 假定咱們正預測的點是 x=0.5,必定要記住 x 的對應值再也不是一個數值,它的對應值變成了向量,因此這是 x=0.5後的新圖像,牢記它變成了一個向量,最上面的是原始數據集;第二個圖顯示了當 k=0.5 時,大部分數據都用於訓練迴歸模型;最下面的圖顯示當 k=0.01 時,僅有不多的局部點被用於訓練迴歸模型。
    • 若是\(|x^{(i)}-x|\approx0\),則\(w_{(i)}\approx1\);若是\(|x^{(i)}-x|\approx\infty\),則\(w^{(i)}\approx0\)

重點來了,我剛開始不明白的就是這裏,上面 兩個注意+圖片解釋 其實已經揭曉了答案

​ 離 x 很近的樣本,權值接近1;而離 x 很遠的樣本,此時權值接近於0,這樣就在 x 局部構成線性迴歸,x 構成的線性迴歸依賴的事 x 周邊的點,而不相似於線性迴歸依賴訓練集中的全部數據。

​ 上圖紅線是某個點 x 基於訓練集中全部數據使用線性迴歸作的結果,黑色直線使用 LWLR 作的結果,因爲在每一個數據都會重複局部加權的過程,而且不斷地每一個點的迴歸係數也在不斷的改變,所以它會很好的擬合數據集,進而消除了線性迴歸擬合很差的缺點。(有點相似極限或者求導或者微積分的思想,總之就是把一個大的物體切割成一大部分,而後對於每一部分進行計算)。

​ 說到了LWLR的優勢,不得不說說它的缺點,上一段講到了訓練集中的每一個數據都會重複局部加權的過程,所以他的計算量是龐大的,而且他的迴歸係數是基於周圍的數據計算出來的,所以下次須要預測某個數據的分類時,須要再一次輸入全部的數據。即線性迴歸算法是參數學習算法,一旦擬合出合適的迴歸係數,對於以後的預測,不須要再使用原始訓練數據集;局部加權線性迴歸算法是非參數學習算法,每次進行預測都須要所有的訓練數據,沒法算出固定的迴歸係數。


​ 最後看一看 線性迴歸和不一樣 k 值的局部加權線性迴歸 對相同數據集的結果。

​ 上圖第一張圖使用的是 k=1 的LWLR(相似於線性迴歸),第二張圖使用的是 k=0.01 的LWLR,第三張圖使用的 k=0.003 的 LWLR。第一張圖明顯欠擬合,第二張圖很合適,第三張圖過擬合。

相關文章
相關標籤/搜索