邏輯迴歸的演算法推導及案例對接
線上性迴歸模型中,我們實際上是建立了一個模型來擬合自變數和因變數之間的線性關係,但是在某些時候,我們要做的可能是一個分類模型,那麼這裡就可能用到線性迴歸模型的變種——邏輯迴歸,本節我們就邏輯迴歸來做一個詳細的說明。
例項引入
我們還是以上一節的例子為例,張三、李四、王五、趙六都要貸款了,貸款時銀行調查了他們的月薪和住房面積等因素,兩個因素決定了貸款款項是否可以立即到賬,下面列出來了他們四個人的工資情況、住房面積和到賬的具體情況:
姓名 | 工資(元) | 房屋面積(平方) | 是否可立即到賬 |
---|---|---|---|
張三 | 6000 | 58 | 否 |
李四 | 9000 | 77 | 否 |
王五 | 11000 | 89 | 是 |
趙六 | 15000 | 54 | 是 |
看到了這樣的資料,又來了一位孫七,他工資是 12000 元,房屋面積是 60 平,那的貸款可以立即到賬嗎?
思路探索
在這個例子中,我們不再是預測貸款金額具體是多少了,而是要對款項是否可以立即到賬做一個分類,分類的結果要麼是“否”要麼是“是”,所以輸出結果我們需要將其對映到一個區間內,讓 0 代表“否”,1 代表“是”,這裡我們就需要用一個函式來幫助我們實現這個功能,它的名字叫做 Sigmoid 函式,它的表示式是這樣的:
$$
g(z) = dfrac{1}{1+e^{-z}}
$$
它的函式影象是這樣的:
它的定義域是全體實數,值域是 (0, 1),當自變數小於 -5 的時候,其值就趨近於 0,當自變數大於 5 的時候,其值就趨近於 1,當自變數為 0 的時候,其值就等於 1/2。
所以我們如果線上性迴歸模型的基礎上加一層 Sigmoid 函式,結果不就可以被轉化為 0 到 1 了嗎?這就很自然而然地轉化為了一個分類模型。
我們知道,線性迴歸模型的表達形式是這樣的:
$$
h{theta}(x) = sum {i=0}^{n}theta_ix_i = theta^Tx
$$
如果我們在它的基礎上加一層 Sigmoid 函式,其表示式就變成了:
$$
h_{theta}(x) = g(theta^Tx) = dfrac{1}{1+e^{-theta^Tx}}
$$
好,現在我們來考慮下這個表示式表達的什麼意思。
我們舉例來說吧,如果這個函式的輸出結果為 1,那麼我們肯定認為結果為“是”。如果輸出結果為 0 呢?我們就當然認為結果為 “否”了,但如果輸出結果為 0.5 呢?我們只能模稜兩可,此時我們既可以判斷為“是”,也可以判斷為“否”,但恰好為 0.5 的概率太小了,多多少少也有點偏差吧。所以如果輸出結果為 0.51,那麼我們怎麼認為?我們認為“是”的概率會更大,否的概率更小,概率是多少?0.49。如果輸出結果是 0.95 呢?“是”的概率是多少?不用多說,必然是 0.95。
因此,我們可以看出來,函式輸出的結果就代表了預測為“是”的概率,也就是真實結果為 1 的概率。我們用公式表達下,這裡我們用 $ h_{theta}(x) $ 表示預測結果,因此對於輸入 x,分類類別為 1 和 0 的概率分別為:
$$
begin{cases}
{theta}(x) \
{theta}(x)end{cases}
$$
還是像線性迴歸一樣,我們需要定義一個代價函式,讓模型來優化這個代價函式。
線上性迴歸中,我們的代價函式是這樣的:
$$
J(theta) = dfrac{1}{2m}sum{i=1}^{m}(h theta(x^{(i)}) – y^{(i)})^2
$$
為什麼是這樣呢?是因為模型的輸出結果和真實結果有一定的偏差,我們用它們的距離差的平方來定義了代價函式。
但是邏輯迴歸不一樣啊,它又不是預測一個具體的數值,而是預測一個分類的概率,所以這裡的代價函式我們可以寫成這樣子:
$$
theta(x), y) = begin{cases}
theta(x)), y = 1 \-log(1- h_theta(x)), y = 0
end{cases}
$$
這裡我們用了對數函式來定義它的損失值。比如當真實值 y 等於 1 的時候,如果我們的函式預測為 1,即 $ h_theta(x) $ 趨近於 1,這就代表預測對了,取對數再取反,結果趨近於 0,代表損失非常小。假如此時我們的函式預測結果趨近於 0,這就代表預測錯了,取對數再取反,結果趨近於正無窮,代表損失特別大。所以,這個代價函式使用對數對預測錯的結果進行了懲罰,偏離越大,其損失越大。
但是這個代價函式不好表示啊,我們想要把它寫成一個表示式該怎麼寫?是這樣的:
$$
Cost(htheta(x), y) = -ylog(h theta(x)) – (1-y)log(1-h_theta(x))
$$
這個式子和上面的式子是完全等價的。
好了,接下來我們計算所有樣本的總的損失函式:
$$
J(theta) = dfrac{1}{m}sum{i=1}^{m}Cost(h theta(x^{(i)}), y^{(i)})\
= -dfrac{1}{m}sum{i=1}^{m}[y^{(i)}log(h theta(x^{(i)})) + (1-y^{(i)})log(1-h_theta(x^{(i)}))]
$$
和線性迴歸類似,這次我們的目的就是找到 $ theta $,使得 $ J(theta) $ 最小。
推導過程
這次我們就不能向上次一樣用直接求偏導數,然後將偏導數置 0 的方法來求解 $ theta $ 了,這樣是無法求解出具體的值的。
我們可以使用梯度下降法來進行求解,也就是一步步地求出 $theta$ 的更新過程,公式如下:
$$
theta_j := theta_j – alphadfrac{partial{J(theta)}}{partial(theta_j)}
$$
這裡面最主要的就是求偏導,過程如下:
$$
j)} \
{i=1}^{n}(y^{(i)}mathop{log}h{theta}(x^{(i)}) + (1-y^{(i)})mathop{log}(1-h {theta}(x^{(i)})))}}{partial(thetaj)} \
{i=1}^{n}(y^{(i)}dfrac{1}{h{theta}(x^{(i)})}dfrac{partial{h {theta}(x^{(i)})}}{partial{thetaj}} + (1-y^{(i)})dfrac{1}{1-h {theta}(x^{(i)})}dfrac{partial{h_{theta}(x^{(i)})}}{partial{thetaj}}) \
{i=1}^{n}[y^{(i)}dfrac{1}{h{theta}(x^{(i)})} + (1-y^{(i)})dfrac{1}{1-h {theta}(x^{(i)})}] dfrac{partial{h_{theta}(x^{(i)})}}{partial{thetaj}} \
{i=1}^{n}[y^{(i)}dfrac{1}{h{theta}(x^{(i)})} + (1-y^{(i)})dfrac{1}{1-h {theta}(x^{(i)})}] h{theta}(x^{(i)})(1-h {theta}(x^{(i)}))dfrac{partial{theta^Tx^{(i)}}}{partial{thetaj}} \
{i=1}^{n}[y^{(i)}(1-h{theta}(x^{(i)})) – (1-y^{(i)})h {theta}(x^{(i)})]xj^{(i)} \
{i=1}^{n}(y^{(i)} – h_{theta}(x^{(i)}))x_j^{(i)}$$
因此:
$$
theta_j := thetaj + dfrac{alpha}{m}sum {i=1}^{n}(y^{(i)} – h_{theta}(x^{(i)}))x_j^{(i)}
$$
這時候我們發現,其梯度下降的推導結果和線性迴歸是一樣的!
程式設計實現
下面我們還是用 Sklearn 中的 API 來實現邏輯迴歸模型,使用的庫為 LogisticRegression,其 API 如下:
class sklearn.linear_model.LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, verbose=0, warm_start=False, n_jobs=1)
引數說明如下:
- penalty:懲罰項,str 型別,可選引數為 l1 和 l2,預設為 l2。用於指定懲罰項中使用的規範。newton-cg、sag 和 lbfgs 求解演算法只支援 L2 規範。L1G 規範假設的是模型的引數滿足拉普拉斯分佈,L2 假設的模型引數滿足高斯分佈,所謂的正規化就是加上對引數的約束,使得模型更不會過擬合(overfit),但是如果要說是不是加了約束就會好,這個沒有人能回答,只能說,加約束的情況下,理論上應該可以獲得泛化能力更強的結果。
- dual:對偶或原始方法,bool 型別,預設為False。對偶方法只用在求解線性多核(liblinear)的 L2懲 罰項上。當樣本數量 > 樣本特徵的時候,dual 通常設定為 False。
- tol:停止求解的標準,float型別,預設為1e-4。就是求解到多少的時候,停止,認為已經求出最優解。
- c:正則化係數 λ 的倒數,float 型別,預設為 1.0。必須是正浮點型數。像 SVM 一樣,越小的數值表示越強的正則化。
- fit_intercept:是否存在截距或偏差,bool 型別,預設為 True。
- intercept_scaling:僅在正則化項為”liblinear”,且fit_intercept 設定為 True 時有用。float 型別,預設為 1。
- class_weight:用於標示分類模型中各種型別的權重,可以是一個字典或者’balanced’字串,預設為不輸入,也就是不考慮權重,即為 None。如果選擇輸入的話,可以選擇 balanced 讓類庫自己計算型別權重,或者自己輸入各個型別的權重。舉個例子,比如對於0,1的二元模型,我們可以定義 class_weight={0:0.9,1:0.1},這樣型別0的權重為 90%,而型別 1 的權重為 10%。如果 class_weight選擇 balanced,那麼類庫會根據訓練樣本量來計算權重。某種型別樣本量越多,則權重越低,樣本量越少,則權重越高。
- random_state:隨機數種子,int型別,可選引數,預設為無,僅在正則化優化演算法為 sag,liblinear時有用。
-
solver:優化演算法選擇引數,只有五個可選引數,即newton-cg, lbfgs, liblinear, sag, saga。預設為liblinear。solver 引數決定了我們對邏輯迴歸損失函式的優化方法,有四種演算法可以選擇,分別是:
- liblinear:使用了開源的 liblinear 庫實現,內部使用了座標軸下降法來迭代優化損失函式。
- lbfgs:擬牛頓法的一種,利用損失函式二階導數矩陣即海森矩陣來迭代優化損失函式。
- newton-cg:也是牛頓法家族的一種,利用損失函式二階導數矩陣即海森矩陣來迭代優化損失函式。
- sag:即隨機平均梯度下降,是梯度下降法的變種,和普通梯度下降法的區別是每次迭代僅僅用一部分的樣本來計算梯度,適合於樣本資料多的時候。
- saga:線性收斂的隨機優化演算法的的變重。
- max_iter:演算法收斂最大迭代次數,int 型別,預設為10。僅在正則化優化演算法為 newton-cg, sag 和 lbfgs 才有用,演算法收斂的最大迭代次數。
- multi_class:分類方式選擇引數,str 型別,可選引數為 ovr 和 multinomial,預設為 ovr。ovr 即前面提到的one-vs-rest(OvR),而 multinomial 即前面提到的 many-vs-many(MvM)。如果是二元邏輯迴歸,ovr 和 multinomial 並沒有任何區別,區別主要在多元邏輯迴歸上。
- verbose:日誌冗長度,int 型別。預設為 0。就是不輸出訓練過程,1 的時候偶爾輸出結果,大於 1,對於每個子模型都輸出。
- warm_start:熱啟動引數,bool 型別。預設為 False。如果為 True,則下一次訓練是以追加樹的形式進行(重新使用上一次的呼叫作為初始化)。
- n_jobs:並行數。int 型別,預設為 1。1 的時候,用 CPU 的一個核心執行程式,2 的時候,用 CPU 的 2 個核心執行程式。為 -1 的時候,用所有 CPU 的核心執行程式。
屬性說明如下:
- coef_:斜率
- intercept_:截距項
我們現在來解決上面的示例,程式碼如下:
from sklearn.linear_model import LogisticRegression x_data = [ [6000, 58], [9000, 77], [11000, 89], [15000, 54] ] y_data = [ 0, 0, 1, 1 ] lr = LogisticRegression() lr.fit(x_data, y_data) x_test = [[12000, 60]] print('Intercept', lr.intercept_) print('Coef', lr.coef_) print('款項是否可以立即到賬', lr.predict(x_test)[0])
這裡我們的 y_data 資料就變了,變成了是非判斷,這裡 0 代表“否”,1 代表“是”。這裡做邏輯迴歸時使用了 LogisticRegression 物件,然後呼叫 fit() 方法進行擬合,擬合完畢之後,使用 [12000, 60] 這條資料作為輸入,讓模型輸出它的預測值。
執行結果:
Intercept [-0.03142387] Coef [[ 0.00603919 -0.72587703]] 款項是否可以立即到賬 1
結果中輸出了截距項和係數項,然後預測了是否可以立即到賬,結果為 1,這表明孫七進行貸款,款項可以立即到賬。
以上就是邏輯迴歸的基本推導和程式碼應用實現。