線性迴歸到底要幹什麼,顧名思義很簡單,即在已有數據集上通過構建一個線性的模型來擬合該數據集特徵向量的各個分量之間的關係,對於需要預測結果的新數據,我們利用已經擬合好的線性模型來預測其結果。關於線性迴歸的方法,現在使用得比較廣泛的就是梯度下降和最小二乘法;我打算把最小二乘法和梯度下降分兩篇博客來寫,這篇就來說一說我對線性迴歸及最小二乘法的理解以及原理實現。
線性模型在二維空間中就是一條直線,在三維空間是一個平面,高維空間的線性模型不好去描述長什麼樣子;如果這個數據集能夠用一個線性模型來擬合它的數據關係,不管是多少維的數據,我們構建線性模型的方法都是通用的。之前看吳恩達機器學習視頻,第一節課講的就是線性迴歸算法,課程裏面提到了一個非常簡單的案例:房屋估價系統。房屋估價系統問題就是當知道房屋面積、臥室個數與房屋價格的對應關係之後,在得知一個新的房屋信息後如何得到對應的新房屋價格,如果我們將房屋面積用x1表示,臥室個數用x2表示,即房屋價格h(x)可以被表示爲房屋面積與臥室個數的一維線性方程:
這就是我們所說的線性模型,當然這個案例中只有房屋面積和臥室個數兩個特徵分量作,現實情況下我們要擬合的模型可能有相當多的特徵分量,那麼線性模型中對應的權重值θ也會有相同多的數量。爲了方便表示我們使用矩陣和向量來表示這些數據
向量θ(長度爲n)中每一個分量都是估計表達式函數h(x)中一個參數,矩陣X(m*n)表示由數據集中每一個樣本的特徵向量所組成的矩陣。其實這樣一個看起來很簡單的式子,它的本質經常就是一個規模極其龐大的線性方程組。如果我們用向量Y(長度爲m)來表示數據集的實際值,如果用實際值來建立一個方程組,參數向量θ中的每一個值就是我們要求的未知量;大多數情況下建立的是一個超定方程組(沒有確定的解),這個時候我們只能求出超定方程組的最優解。通過建立一個損失函數來衡量估計值和實際之間的誤差的大小,我們將最小化損失函數作爲一個約束條件來求出參數向量的最優解。
函數J(θ)即爲損失函數,它計算出數據集中每一個樣例的估計值和實際值的平方差並求取平均。然後就是我們的最小二乘法登場了,最小二乘法通過數學推導(後面給出證明)可以直接得到一個標準方程,這個標準方程的解就是最優的參數向量。
推導方法
最小二乘法通過數學推導出標準方程的過程其實非常簡單,知乎上有一篇博客https://zhuanlan.zhihu.com/p/22474562寫得很詳細,這裏借鑑一下:
更詳細的推導方法
通過正規方程計算得到最優的參數向量之後,就可以確定線性迴歸方程了,預測只需要將特徵向量代入到迴歸方程之中,就可以計算出估計值了。
既然弄清了原理,那麼實現就會顯得非常簡單;考慮到這個算法過程中使用矩陣乘法的次數很多,所以我使用了python語言以及調用numpy庫來實現線性迴歸的算法,這裏使用了sklearn庫中的波士頓房價數據集,代碼如下
import numpy as np
from sklearn.datasets import load_boston # 導入博士頓房價數據集
from sklearn import linear_model
class LinerRegression:
M_x = [] #
M_y = [] #
M_theta = [] # 參數向量
trained = False
def __init__(self):
pass
def regression(self, data, target):
self.M_x = np.mat(data)
# 每個向量添加一個分量1,用來對應係數θ0
fenliang = np.ones((len(data), 1))
self.M_x = np.hstack((self.M_x, fenliang))
self.M_y = np.mat(target)
M_x_T = self.M_x.T # 計算X矩陣的轉置矩陣
self.M_theta = (M_x_T * self.M_x).I * M_x_T * self.M_y.T # 通過最小二乘法計算出參數向量
print('Start to train it with my own implementation of liearRegression')
print(self.M_theta)
self.trained = True
def predict(self, vec):
if not self.trained:
print("You haven't finished the regression!")
return
M_vec = np.mat(vec)
fenliang = np.ones((len(vec), 1))
M_vec = np.hstack((M_vec, fenliang))
estimate = np.matmul(M_vec, self.M_theta)
return estimate
def test_my_linear_regression():
# 從sklearn的數據集中獲取相關向量數據集data和房價數據集target
data, target = load_boston(return_X_y=True)
lr = LinerRegression()
lr.regression(data, target)
# 提取一批樣例觀察一下擬合效果
test = data[::51]
M_test = np.mat(test)
real = target[::51] # 實際數值real
estimate = np.array(lr.predict(M_test)) # 迴歸預測數值estimate
# 打印結果
for i in range(len(test)):
print("實際值:", real[i], " 估計值:", estimate[i, 0])
def test_sklearn_liear_regression():
data, target = load_boston(return_X_y=True)
clf = linear_model.LinearRegression()
clf.fit(data, target)
print('Start to train it with Sklearn ')
print(clf.coef_)
print(clf.intercept_)
if __name__ == '__main__':
test_sklearn_liear_regression()
test_my_linear_regression()
運行結果如下:
Start to train it with Sklearn
[-1.08011358e-01 4.64204584e-02 2.05586264e-02 2.68673382e+00
-1.77666112e+01 3.80986521e+00 6.92224640e-04 -1.47556685e+00
3.06049479e-01 -1.23345939e-02 -9.52747232e-01 9.31168327e-03
-5.24758378e-01]
36.45948838509001
Start to train it with my own implementation of liearRegression
[[-1.08011358e-01]
[ 4.64204584e-02]
[ 2.05586264e-02]
[ 2.68673382e+00]
[-1.77666112e+01]
[ 3.80986521e+00]
[ 6.92224640e-04]
[-1.47556685e+00]
[ 3.06049479e-01]
[-1.23345939e-02]
[-9.52747232e-01]
[ 9.31168327e-03]
[-5.24758378e-01]
[ 3.64594884e+01]]
實際值: 24.0 估計值: 30.003843377016256
實際值: 20.5 估計值: 23.97222284868958
實際值: 18.6 估計值: 19.79013683546337
實際值: 19.4 估計值: 17.286018936122648
實際值: 50.0 估計值: 43.18949843697001
實際值: 20.9 估計值: 21.695808865539043
實際值: 33.4 估計值: 35.56226856966765
實際值: 21.7 估計值: 22.718066074783085
實際值: 17.2 估計值: 13.70756369210629
實際值: 20.0 估計值: 18.51247609292085
可以看到用Sklearn裏LinearRegarssion訓練得到的參數其實和我實現的結果是一樣的。
另外
絕大多數樣例通過線性迴歸模型預測的結果與真實結果十分接近,但是存在有一定的誤差,可以接受。
參考資料
https://blog.csdn.net/qq_32864683/article/details/80488523
https://blog.csdn.net/perfect_accepted/article/details/78383434