[機器學習]邏輯迴歸公式推導及其梯度下降法的Python實現

一般來說,二項邏輯斯諦迴歸模型是一個二分類判別模型,由條件概率分佈P(Y|X) 表示,隨機變量X 爲實數,Y 取值0或者1。我們通過比較P(Y=1|x)P(Y=0|x) 值大小來判斷給定x的類別爲1還是0。

從線性模型推導

我們先說廣義的線性迴歸:y=wx+b ,這裏 y 爲迴歸的目標,x爲輸入的數據,wb 分別爲需要學習的參數和偏置,我們簡化爲y=wx ,此時w 爲參數向量,包括了偏置b 。如果此時我們把線性迴歸的目標y 設爲一個事件的對數機率(log odds),即事件發生的概率p 與不發生的概率1p 的比值再取對數,也就是:

log(p1p)=wx

那麼這就是邏輯斯諦迴歸模型,此時p 可以爲類別1事件發生的概率P(Y=1|x) , 則1p 爲類別0事件發生的概率P(Y=0|x) ,我們用p 表示上述式子:
p=exp(wx)1+exp(wx)=σ(wx)

就得到了我們平時接觸最多的logistic函數(σ )的形式,那麼換一種角度理解,這個模型就是一個線性模型wx 經過一個非線性變換σ 得到的,更通俗的說,是一個神經網絡,這個網絡除了輸入層只有一個輸出神經元,並且使用了sigmoid激活函數σ ,最後輸出的p表示類別爲1的概率。

極大似然法估計與交叉墒

學習邏輯斯諦迴歸模型時,對於給定的數據集T={(x1,y1),(x2,y2),,(xN,yN)} ,我們通過極大似然估計法來估計出一套參數w^ ,使模型對於此數據集中樣本值的發生概率最大,也就是使模型能儘可能擬合現有數據集中現有的樣本。

由於數據集中每個樣本(xi,yi) 之間相互獨立,用p(xi) 表示模型判別xi 爲類別1的概率,則1p(xi) 表示模型判別xi 爲類別0的概率,那麼整個數據集T 所有樣本發生的概率爲每個樣本對應實際類別概率的連乘:

1N[p(xi)]yi[1p(xi)]1yi

這就是我們需要最大化的似然函數,由於連乘的性質,我們一般採用對數似然函數將乘法變成加法,於是有:
L(w)=1N[yilogp(xi)+(1yi)log(1p(xi))]

L(w) 求極大值,得到對w的估計值w^

從另外一個角度來看,帶負號的L(w) 其實非常像交叉墒:交叉墒在一定程度上是衡量着兩個分佈之間的差異,這裏具體是指p(xi)yi 。當模型學到的p(xi) 和真實目標分佈yi 越相近,模型的效果越好,交叉墒越小。理想情況下,當兩個分佈完全一致時,此時相對墒爲0,交叉墒達到最低值,即真實目標分佈的墒 yilog(yi) ,詳情見如何通俗的解釋交叉熵與相對熵?。當帶負號的L(w) 達到極小值時,也就是L(w) 達到極大值,此時的模型參數是理想的,也是我們最終需要達到的目標,這與我們前面用似然函數估計分析的結果一致,可以看出這兩者實際上是相通的。

梯度下降法最優化

我們把求L(w) 極大值問題轉化爲求L(w) 的極小值的最優化問題。最優化的方法通常是梯度下降法和牛頓法,我們具體給出梯度下降法的做法。我們把概率p(xi) 表示爲非線性函數σ(wxi) ,因此目標函數重新寫成如下:

L=iNyilogσ(wxi)(1yi)log(1σ(wxi))

wxi 進行求導,有:

(1)L(wxi)=L(σ(wxi))(σ(wxi))(wxi)(2)=[yi1σ(wxi)(1yi)11σ(wxi)]σ(wxi)(1σ(wxi))(3)=yi(1σ(wxi))+(1yi)σ(wxi)(4)=yi+yiσ(wxi)+σ(wxi)yiσ(wxi)(5)=σ(wxi)yi

其中利用了sigmoid函數的導數σ=σ(1σ) 。從直觀上解釋:對於單個樣本xi , 線性函數wxi 的梯度爲其非線性激活後的值減去真實標籤值,也就是輸出值p(xi) 減去yi ,更具體來說,當yi 爲1時,梯度爲p(xi)1 ,當yi 爲0時,梯度爲p(xi)

如果用批量梯度下降法,那麼每個epoch,參數w 的梯度爲:

(6)L(w))=iNL(wxi)(wxi)w(7)=iN(σ(wxi)yi)×xi

Python實現(批量梯度下降法)

我們使用iris數據集中的前100行數據,實現一個簡單的邏輯迴歸二分類器,使用批量梯度下降法:

from sklearn import datasets
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from numpy.linalg import inv

iris = datasets.load_iris()
X = iris.data[:100, :]
y = iris.target[:100].reshape((100, -1))


def logit(x):
    return 1. / (1 + np.exp(-x))


m, n = X.shape
alpha = 0.0065 // 步長
w = np.random.random((n, 1)) // 參數矩陣
maxCycles = 30
J = pd.Series(np.arange(maxCycles, dtype=float))

for i in range(maxCycles):
    h = logit(np.dot(X, w)) // 輸出估計值h
    J[i] = -(1 / 100.) * np.sum(y * np.log(h) + (1 - y) * np.log(1 - h)) // 記錄目標函數的值
    error = h - y //計算wx的梯度,輸出值減去真實值
    grad = np.dot(X.T, error) //計算w的梯度
    w -= alpha * grad // 更新參數w,使用負梯度最小化J
print w
J.plot()
plt.show()

牛頓法與梯度下降法比較

牛頓法是直接利用函數有極小點的必要條件,即一階導數 f’導數爲零,所以每次迭代後的點 xk+1 的特點就是 f(xk+1)=0 ,又由於一階導數可以通過二階導數與步長的乘積來計算(二階泰勒展開):f(xk+1)=f(xk)+f(xk)(xk+1xk) ,因此就有 f(xk)+f(xk)(xk+1xk)=0 即每次更新的步長等於 Δx=xk+1xk=f(xk)/f(xk) ,這個 Δx 在梯度下降法中的體現就是 α ,只不過梯度下降法每次更新都是以一個非常小的固定步長 α (一般情況下)在更新,而牛頓法一步到位直接找到一個相對最優的點,利用了二階導數的信息,因此迭代次數更少,收斂快。

舉例子,比如一個簡單的強凸函數 f=x2 , 無論起始點是哪,牛頓法總能一次迭代就找到最小值點0, 而梯度下降法只能根據步長和起始點得位置慢慢逼近0,但是實際上函數 f 可能要複雜得多,函數可能是整體上非凸,但是局部是凸函數(比如最優點附近),直接用牛頓法迭代多次也不能保證收斂到最優點,因此需要先用梯度下降找到一個相對好的解後再用牛頓法可能效果比較好(根據曾文俊的回答),從這裏我們也可以看出牛頓法對函數的性質以及初始點的位置選擇比較挑剔,另外一個是二階導數矩陣的逆矩陣計算量比較大(當 xk 爲參數矩陣時,此時 f(xk) 爲一個二階偏導數矩陣,即Hesse 矩陣),通常使用擬牛頓法。

個人思考:前面的 f=x2 最大階數只有2,我們利用二階導數能完美解決它的最優化問題;但是當 f 的階數 n 大於2時,此時用泰勒展開式展開到2階(牛頓法只展開到2階),後面還有一個高階無窮小 Rn ,因此現在展開的等式兩邊都是約等於的關係(如果不考慮 Rn ),即可推出 f(xk+1)f(xk)+f(xk)(xk+1xk) ,嚴格上來說,此時求得的 Δx 並不能使參數更新到最優點,只能說是“相對最優”的點,所以多次迭代還是有必要的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章