大家好,我是東哥。
線性迴歸作為監督學習中經典的迴歸模型之一,是初學者入門非常好的開始。巨集觀上考慮理解性的概念,我想我們在初中可能就接觸過,y=ax,x為自變數,y為因變數,a為係數也是斜率。如果我們知道了a係數,那麼給我一個x,我就能得到一個y,由此可以很好地為未知的x值預測相應的y值。這很符合我們正常邏輯,不難理解。
那統計學中的線性迴歸是如何解釋的呢?
對於統計模型線性迴歸,我想從以下六個方面來展開,並分兩篇文章進行詳細解讀:
- 線性迴歸模型定義
- 線性迴歸的損失函式
- 線性迴歸引數估計
- 線性迴歸預測
- 線性迴歸擬合優度
- 線性迴歸假設檢驗
- 線性迴歸診斷
線性迴歸模型定義
線性迴歸按變數數量的多少可以分為:一元線性迴歸(簡單線性迴歸)和多元線性迴歸。
一元線性迴歸,也就是有一個自變數,其模型可以表示如下:
公式中引數解釋如下:
x:自變數
y:因變數
β 0:截距
β 1:變數回歸係數
ϵ:誤差項的隨機變數1
這些引數中,(β 0+β 1x*)反映了由於x的變化而引起的y的線性變化;ϵ反映了除了x和y之間的線性關係之外的隨機因素對y的影響,是不能由x和y之間的線性關係所解釋的變異性。可以這麼來理解ϵ:我們對y的預測是不可能達到與真實值完全一樣的,這個真實值只有上帝知道,因此必然會產生誤差,我們就用ϵ來表示這個無法預測的誤差。*
同樣的,多元線性迴歸模型的表示如下:
我們通過引入了ϵ可以讓模型達到完美狀態,也就是理論的迴歸模型。但是我們要如何定義這個無法預測的誤差項呢?為此,偉人們提出了一些假設條件:
在統計學中,高斯-馬爾可夫定理陳述的是:在誤差零均值,同方差,且互不相關的線性迴歸模型中,迴歸係數的最佳無偏線性估計(BLUE)就是最小方差估計。
總結一下,有如下幾個主要的假設條件:
(1)誤差項ϵ是一個期望為0的隨機變數,即E(ϵ)=0
(2)對於自變數的所有值,ϵ的方差σ^2 都相同
(3)誤差項ϵ是一個服從正態分佈的隨機變數,且相互獨立,即ϵ~N(0,σ^2)
ϵ正態性意味著對於給定的自變數,因變數y也是一個服從正態分佈的隨機變數。根據迴歸模型的假設,有如下多元迴歸方程:
線性迴歸的損失函式
從樣本資料考慮,如果想讓我們預測值儘量準確,那麼我們就必須讓真實值與預測值的差值最小,即讓誤差平方和ϵ最小,用公式來表達即:
用平方而沒用誤差絕對值是因為:平方對於後續求導比較方便。
雖然我們得到了損失函式,但是如果從統計理論的角度出發來推導損失函式,我認為更有說服力,也能更好地理解線性迴歸模型,以及為什麼開始要提出那些假設條件。
根據上面假設條件:ϵ 服從均值為0,方差為σ的正態分佈,且獨立,因此隨機變數ϵ 的概率密度函式(正態分佈的概率密度函式)為:
我們把前面的多元線性迴歸模型簡單地變換一下,如下:
然後將得到的ϵ公式帶入上面概率密度函式:
有了概率密度函式,我們自然會想到用最大似然估計推導損失函式:
然後我們將似然函式取對數,這樣可以將概率密度的乘法轉換為加法:
再然後我們對似然函式取最大值,即最大化似然函式:
這樣我們就從統計理論的角度得到了我們要找的損失函式,與我們最小化誤差平方和得到的結果是一樣的,也從側面證實了前面提出假設的正確性。因此,多元線性迴歸模型的損失函式為:
公式裡的1/2對損失函式沒有影響,只是為了能抵消求導後的乘數2。
線性迴歸引數估計
損失函式只是一種策略,有了策略我們還要用適合的演算法進行求解。線上性迴歸模型中,求解損失函式就是求與自變數相對應的各個迴歸係數和截距。有了這些引數,我們才能實現模型的預測(輸入x,給出y)。
對於誤差平方和損失函式的求解方法有很多,典型的如最小二乘法,梯度下降等。下面我們分別用這兩種方法來進行求解。
最小二乘法
最小二乘法可以將誤差方程轉化為有確定解的代數方程組(其方程式數目正好等於未知數的個數),從而可求解出這些未知引數。這個有確定解的代數方程組稱為最小二乘法估計的正規方程。
我們將代數方程組用矩陣來代替可以簡化推導過程,以及程式碼實現。
這裡會涉及到矩陣求導的用法,詳細介紹請看下面wiki的參考連結:
https://en.wikipedia.org/wiki...
我們令上面得到的公式等於0,即可得到最終的求解:
Python中對於矩陣的各種操作可以通過Numpy庫的一些方法來實現,非常方便。但在這個程式碼實現中需要注意:X矩陣不能為奇異矩陣,否則是無法求解矩陣的逆的。下面是手擼最小二乘法的程式碼實現部分。
def standRegres(xArr,yArr):
"""
函式說明:計算迴歸係數w Parameters: xArr - x資料集 yArr - y資料集 Returns: ws - 迴歸係數 """
xMat = np.mat(xArr); yMat = np.mat(yArr).T
#根據文中推導的公示計算迴歸係數
xTx = xMat.T * xMat
if np.linalg.det(xTx) == 0.0:
print("矩陣為奇異矩陣,不能求逆")
return
ws = xTx.I * (xMat.T*yMat)
return ws
梯度下降法
梯度下降是另一種常用的方法,可以用來求解凸優化問題。它的原理有別於最小二乘法,它是通過一步步迭代(與最小二乘法的區別在後面介紹)求解,不斷逼近正確結果,直到與真實值之差小於一個閾值,從而得到最小化損失函式的模型引數值的。它的公式如下:
對於損失函式的梯度(即求偏導的過程),上面在最小二乘法部分已經給出推導過程和結果。不同的是,我們不會將公式等於0來求極值,而是帶入上面梯度下面公式來迭代完成求解,以下是梯度下降矩陣形式的最終求解結果。
最小二乘法 vs 梯度下降法
通過上面推導,我們不難看出,二者都對損失函式的迴歸係數進行了求偏導,並且所得到的推導結果是相同的,那麼究竟哪裡不同呢?
如果仔細觀察,可以觀察到:最小二乘法通過使推導結果等於0,從而直接求得極值,而梯度下降則是將推導結果帶入迭代公式中,一步一步地得到最終結果。簡單地說,最小二乘法是一步到位的,而梯度下降是一步步進行的。
因而通過以上的異同點,總結如下
最小二乘法:
- 得到的是全域性最優解,因為一步到位,直接求極值,因而步驟簡單
- 線性迴歸的模型假設,這是最小二乘方法的優越性前提,否則不能推出最小二乘是最佳(即方差最小)的無偏估計
梯度下降法:
- 得到的是區域性最優解,因為是一步步迭代的,而非直接求得極值
- 既可以用於線性模型,也可以用於非線性模型,沒有特殊的限制和假設條件
線性迴歸預測
上面我們已經手擼了最小二乘法和梯度下降法求解誤差平方和損失函式的過程,即我們通過以上演算法已經得到了我們想要的引數值。當然,我們也可以使用statsmodels或者sklearn庫中已經被封裝好了的模型來進行預測。不過,為了更好的瞭解模型,優化演算法,而不僅僅是做一個調包俠,我們最好對每種演算法都自己實現一遍。
為了更好的說明整個建模到預測的過程,我們通過一個例子來詳細說明。對於一個資料集,我們通過自己手擼的最小二乘法來建模,求解引數然後進行預測。
class LeastSquared(object):
def __init__(self):
self.xArr = []
self.yArr = []
self.params = []
self.y_predict = []
def fit(self,xArr,yArr):
self.xArr = xArr
self.yArr = yArr
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
xTx = xMat.T*xMat
if np.linalg.det(xTx) == 0.0:
print('矩陣為奇異矩陣')
params = xTx.I*(xMat.T*yMat)
self.params = params
def predict(self,x_new):
y_predict = x_new*self.params
self.y_predict = y_predict
return y_predict
可以看到這是一個簡單的二維平面,藍色代表一個變數X和因變數Y的散點圖,紅色是我們通過最小二乘法擬合出來的直線。如果是多自變數,那麼擬合結果將是一個平面,或者超平面。使用這個模型,我們就能對未知的X值進行預測。
然後,我們在x的範圍內再取10個隨機數,並進行預測感受一下。
# 生成最小二乘法類
xArr, yArr = loadDataSet('ex0.txt')
ls = LeastSquared()
ls.fit(xArr,yArr) #訓練模型
y_predict = ls.predict(xArr) #預測模型
# 在x範圍內,隨機生成10個新的x值
x_min = np.min(np.array(xArr)[:,1])
x_max = np.max(np.array(xArr)[:,1])
x_random = np.random.uniform(x_min,x_max,[10,1])
x_new = np.c_[np.ones(10),x_random.flatten()]
y_new = ls.predict(x_new)
y_new = y_new.flatten().tolist()[0]
x_new = x_random.flatten().tolist()
# 視覺化
n = len(xArr)
xcord = [];ycord = [];y_hat = []
for i in range(n):
xcord.append(xArr[i][1])
ycord.append(yArr[i])
y_hat.append(y_predict.tolist()[i][0])
fig = plt.figure()
#新增subplot
ax = fig.add_subplot(111)
#繪製樣本點
ax.plot(xcord, y_hat, c = 'red')
ax.scatter(xcord, ycord, s = 20, c = 'blue',alpha = .5)
ax.scatter(x_new,y_new, s=150, c='r', alpha = 0.8)
#繪製title
plt.title('LeastSquareMethod')
plt.xlabel('X')
plt.show()
這時我們看到,生成的10個隨機數都在我們的擬合直線上,對應的y值就是我們的預測值。同樣的,我們也手擼了梯度下降演算法進行的求解過程,二者得到的結果引數幾乎相等。二者視覺化效果如下所示(可以看到兩個擬合直線是重合的,紅色和綠色):
二者所得引數對比如下,其中梯度下降迭代了500次,可以看到引數結果是幾乎一樣的。
#最小二乘法
ls.params
>>matrix([[3.00774324],
[1.69532264]])
#梯度下降法,迭代500次
gd.params
>>matrix([[3.00758726],
[1.69562035]])
總結
本篇主要介紹了線性迴歸的前幾個部分:模型定義假設,模型引數估計,模型預測。但是預測完模型之後,我們並不知道結果時好時壞,並且我們也不知道開始的假設是否成立,這些內容涉及模型擬合優度,模型假設檢驗,和模型診斷,將在下一篇進行介紹。
參考:《機器學習實戰》Peter Harrington
《統計學》賈俊平
原創不易,覺得不錯點個贊。
另外,歡迎關注我的原創公眾號:Python資料科學
資料科學學習網站:datadeepin