機器學習之線性迴歸法

在統計學中,線性迴歸(Linear regression)是利用稱爲線性迴歸方程的最小二乘函數對一個或多個自變量和因變量之間關係進行建模的一種迴歸分析維基百科python

簡單線性迴歸

當只有一個自變量的時候,成爲簡單線性迴歸。git

簡單線性迴歸模型的思路

爲了獲得一個簡單線性迴歸模型,假設存在以房屋面積爲特徵,以價格爲樣本輸出,包含四個樣本的樣本集,如圖:github

clipboard.png

尋找一條直線,最大程度上擬合樣本特徵與樣本輸出之間的關係。算法

假設最佳擬合的直線方程爲:$y = ax + b$,則對於樣本特徵 $x$ 的每個取值 $x^{(i)}$ 的預測值爲:$\hat{y}^{(i)} = ax^{(i)} +b$。而咱們但願的就是真值 $y^{(i)}$ 和預測值 $\hat{y}^{(i)}$ 之間的差距儘可能小。函數

能夠用 $|y^{(i)} - \hat{y}^{(i)}|$ 表示二者之間的差距,對於全部的樣本,使用求和公式求和處理:學習

$$ \sum_{i=1}^{m}|y^{(i)} - \hat{y}^{(i)}| $$測試

可是這個公式有一個問題,不容易求導,爲了解決這個問題,可先對 $|y^{(i)} - \hat{y}^{(i)}|$ 進行平方,如此最後的公式就變成了:優化

$$ \sum_{i=1}^{m}(y^{(i)} - \hat{y}^{(i)})^2 $$ui

最後,替換掉 $\hat{y}^{(i)}$ ,即爲:spa

$$ \sum_{i=1}^{m}(y^{(i)} - ax^{(i)}-b)^2 $$

所以,找到的一個簡單線性迴歸模型就是找到合適的 a 和 b,使得該函數的值儘量的小,該函數也稱爲損失函數(loss function)。

最小二乘法

找到合適的 a 和 b,使得 $\sum_{i=1}^{m}(y^{(i)} - ax^{(i)}-b)^2$ 的值儘量的小,這樣的方法稱爲最小二乘法。

如何求 a 和 b 呢?令該函數爲 $J(a, b)$,分別使對 a 和 b 求導的結果爲0。

對 b 求導:$\frac{\partial{J(a, b)}}{\partial{b}} = \sum_{i=1}^{m}2(y^{(i)} - ax^{(i)}-b)(-1) = 0$,得:

$$ b = \overline{y}-a\overline{x} $$

對 a 求導:$\frac{\partial{J(a, b)}}{\partial{a}} = \sum_{i=1}^{m}2(y^{(i)} - ax^{(i)}-b)(-x^{(i)}) = 0$,得:

$$ a = \frac{\sum_{i=1}^{m}(x^{(i)}-\overline{x})(y^{(i)}-\overline{y})}{\sum_{i=1}^{m}(x^{(i)}-\overline{x})^2} $$

注:這裏略去了公式的推導過程。

簡單線性迴歸的實現

有了數學的幫助,實現簡單線性迴歸就比較方便了。

首先聲明一個樣本集:

import numpy as np

x = np.array([1., 2., 3., 4., 5.])
y = np.array([1., 3., 2., 3., 5.])

公式中用到了 x 和 y 的均值:

x_mean = np.mean(x)
y_mean = np.mean(y)

求 a 和 b 的值有兩種方法。第一種是使用 for 循環:

# 分子
num = 0.0

# 分母
d = 0.0

for x_i, y_i in zip(x, y):
    num += (x_i - x_mean) * (y_i - y_mean)
    d += (x_i - x_mean) ** 2
    
a = num / d
b = y_mean - a * x_mean

第二種是使用矩陣乘:

num = (x - x_mean).dot(y - y_mean)
d = (x - x_mean).dot(x - x_mean)

a = num / d
b = y_mean - a * x_mean

注:使用矩陣乘效率更高。

求出了 a 和 b,簡單線性模型就有了:$\hat{y} = a*x + b$。對當前示例做圖表示:​

clipboard.png

衡量線性迴歸法的指標

偏差

一個訓練後的模型一般都會使用測試數據集測試該模型的準確性。對於簡單線性歸回模型固然可使用 $\sum_{i=1}^{m}(y_{test}^{(i)} - \hat{y}_{test}^{(i)})^2$ 來衡量,可是它的取值和測試樣本個數 m 存在聯繫,改進方法很簡單,只需除以 m 便可,即均方偏差(Mean Squared Error):

$$ MSE:\frac{1}{m}\sum_{i=1}^{m}(y_{test}^{(i)} - \hat{y}_{test}^{(i)})^2 $$

np.sum((y_predict - y_true) ** 2) / len(y_true)

值得一提的是 MSE 的量綱是樣本單位的平方,有時在某些狀況下這種平方並非很好,爲了消除量綱的不一樣,會對 MSE 進行開方操做,就獲得了均方根偏差(Root Mean Squared Error):

$$ RMSE:\sqrt{\frac{1}{m}\sum_{i=1}^{m}(y_{test}^{(i)} - \hat{y}\_{test}^{(i)})^2} = \sqrt{MSE_{test}} $$

import math

math.sqrt(np.sum((y_predict - y_true) ** 2) / len(y_true))

還有一種衡量方法是平均絕對偏差(Mean Absolute Error),對測試數據集中預測值與真值的差的絕對值取和,再取一個平均值:

$$ MAE:\frac{1}{m}\sum_{i=1}^{m}|y_{test}^{(i)} - \hat{y}_{test}^{(i)}| $$

np.sum(np.absolute(y_predict - y_true)) / len(y_true)

注:Scikit Learn 的 metrics 模塊中的 mean_squared_error() 方法表示 MSE,mean_absolute_error() 方法表示 MAE,沒有表示 RMSE 的方法。

R Squared

更近一步,MSE、RMSE 和 MAE 的侷限性在於對模型的衡量只能作到數值越小表示模型越好,而一般對模型的衡量使用1表示最好,0表示最差,所以引入了新的指標:R Squared,計算公式爲:

$$ R^2 = 1 - \frac{SS_{residual}}{SS_{total}} $$

$SS_{residual} = \sum_{i=1}^{m}(\hat{y}^{(i)} - y^{(i)})^2$,表示使用模型產生的錯誤;$SS_{total} = \sum_{i=1}^{m}(\overline{y} - y^{(i)})^2$,表示使用 $y = \overline{y}$ 預測產生的錯誤。

更深刻的講,對於每個預測樣本的 x 的預測值都爲樣本的均值 $\overline{y}$ ,這樣的模型稱爲基準模型;當咱們的模型等於基準模型時,$R^2$ 的值爲0,當咱們的模型不犯任何錯誤時 $R^2$ 獲得最大值1。

$R^2$ 還能夠進行轉換,轉換結果爲:

$$ R^2 = 1 - \frac{MSE(\hat{y}, y)}{Var(y)} $$

實現也很簡單:

1 - np.sum((y_predict - y_true) ** 2) / len(y_true) / np.var(y_true)

注:Scikit Learn 的 metrics 模塊中的 r2_score() 方法表示 R Squared。

多元線性迴歸

多元線性迴歸模型的思路

當有不僅一個自變量時,即爲多元線性迴歸,如圖:

clipboard.png

對於有 n 個自變量來講,咱們想得到的線性模型爲:

$$ y = \theta_{0} + \theta_{1}x_{1} + \theta_{2}x_{2} + ... + \theta_{n}x_{n} $$

根據簡單線性迴歸的思路,咱們的目標即爲:

找到 $\theta_{0}$,$\theta_{1}$,$\theta_{2}$,...,$\theta_{n}$,使得 $\sum_{i=1}^{m}(y^{(i)} - \hat{y}^2)^2$ 儘量的小,其中 $\hat{y}^{(i)} = \theta_{0} + \theta_{1}X_{1}^{(i)} + \theta_{2}X_{2}^{(i)} + ... + \theta_{n}X_{n}^{(i)}$ 。

$\hat{y}^{(i)}$:訓練數據中第 i 個樣本的預測值;$X_{j}^{(i)}$:訓練數據中第 i 個樣本的第 j 個自變量。

若是用矩陣表示即爲:

$$ \hat{y}^{(i)} = X^{(i)}·\theta $$

其中:${X^{(i)} = (X_{0}^{(i)},X_{1}^{(i)},X_{2}^{(i)},...,X_{n}^{(i)}), X_{0}^{(i)}\equiv1}$;$\theta = (\theta_{0}, \theta_{1}, \theta_{2},..., \theta_{n})^T$。

更進一步,將 $\hat{y}^{(i)}$ 也使用矩陣表示,即爲:

$$ \hat{y} = X_b·\theta $$

其中:$X_b = \begin{pmatrix} 1 & X_1^{(1)} & X_2^{(1)} & \cdots & X_n^{(1)} \\\ 1 & X_1^{(2)} & X_2^{(2)} & \cdots & X_n^{(2)} \\\ \cdots & & & & \cdots \\\ 1 & X_1^{(m)} & X_2^{(m)} & \cdots & X_n^{(m)} \end{pmatrix}$,$\theta = \begin{pmatrix} \theta_0 \\\ \theta_1 \\\ \theta_2 \\\ \cdots \\\ \theta_n \end{pmatrix} $

所以,咱們目標就成了:使 $(y-X_b·\theta)^T(y-X_b·\theta)$ 儘量小。而對於這個公式的解,稱爲多元線性迴歸的正規方程解(Nomal Equation):

$$ \theta = (X_b^TXb)^{-1}(X_b^Ty) $$

實現多元線性迴歸

將多元線性迴歸實如今 LinearRegression 類中,且使用 Scikit Learn 的風格。

_init_() 方法首先初始化線性迴歸模型,_theta 表示 $\theta$,interception_ 表示截距,chef_ 表示迴歸模型中自變量的係數:

class LinearRegression:
    def __init__(self):
        self.coef_ = None
        self.interceiption_ = None
        self._theta = None

fit_normal() 方法根據訓練數據集訓練模型,X_b 表示添加了 $X_{0}^{(i)}\equiv1$ 的樣本特徵數據,而且使用多元線性迴歸的正規方程解求出 $\theta$:

def fit_normal(self, X_train, y_train):
    X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
    self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)

    self.interception_ = self._theta[0]
    self.coef_ = self._theta[1:]

    return self

predict() 方法爲預測方法,一樣使用了矩陣乘:

def predict(self, X_predict):
    X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
    return X_b.dot(self._theta)

score() 根據給定的測試數據集使用 R Squared 指標計算模型的準確度:

def score(self, X_test, y_test):
    y_predict = self.predict(X_test)
    return r2_score(y_test, y_predict)
Scikit Learn 中的線性迴歸實現放在 linear_model 模塊中,使用方法以下:

from sklearn.linear_model import LinearRegression

線性迴歸的特色

線性迴歸算法是典型的參數學習的算法,只能解決迴歸問題,其對數據具備強解釋性。

缺點是多元線性迴歸的正規方程解 $\theta = (X_b^TXb)^{-1}(X_b^Ty)$ 的時間複雜度高,爲 $O(n^3)$,可優化爲 $O(n^{2.4})$。

源碼地址

Github | ML-Algorithms-Action

相關文章
相關標籤/搜索