雖然叫做“迴歸”,但是這個算法是用來解決分類問題的。迴歸與分類的區別在於:迴歸所預測的目標量的取值是連續的(例如房屋的價格);而分類所預測的目標變量的取值是離散的(例如判斷郵件是否爲垃圾郵件)。當然,爲了便於理解,我們從二值分類(binary classification)開始,在這類分類問題中,y只能取0或1。更好的理解問題,先舉個小例子:假如我們要製作一個垃圾郵件過濾系統,如果一封郵件是垃圾系統,y=1,否則y=0 。給定訓練樣本集,當然它們的特徵和標籤都已知,我們就是要訓練一個分類器,將它們分開。
線性迴歸的假設(hypotheses)函數爲:
爲了簡便,記,那麼
邏輯迴歸本質上是線性迴歸,只是在特徵到結果的映射中加入了一層邏輯函數g(z),即先把特徵線性求和,然後使用函數g(z)作爲假設函數來預測。g(z)可以將連續值映射到0 和1。
g(z)爲sigmoid function.
則
sigmoid function 的導數如下:
邏輯迴歸用來分類0/1 問題,也就是預測結果屬於0 或者1 的二值分類問題。這裏假設了二值滿足伯努利分佈,也就是
其也可以寫成如下的形式:
對於訓練數據集,特徵數據x={x1, x2, … , xm}和對應的分類標籤y={y1, y2, … , ym},假設m個樣本是相互獨立的,那麼,極大似然函數爲:
log似然爲:
如何使其最大呢?與線性迴歸類似,我們使用梯度上升的方法(求最小使用梯度下降),那麼
。
如果只用一個訓練樣例(x,y),採用隨機梯度上升規則,那麼隨機梯度上升更新規則爲:
2 梯度下降算法
梯度下降算法的僞代碼如下:
################################################
初始化迴歸係數爲1
重複下面步驟直到收斂{
計算整個數據集的梯度
使用alpha x gradient來更新迴歸係數
}
返回迴歸係數值
################################################
注:因爲本文中是求解的Logit迴歸的代價函數是似然函數,需要最大化似然函數。所以我們要用的是梯度上升算法。但因爲其和梯度下降的原理是一樣的,只是一個是找最大值,一個是找最小值。找最大值的方向就是梯度的方向,最小值的方向就是梯度的負方向。另外,最大似然可以通過取負對數,轉化爲求最小值。
2.2 隨機梯度下降SGD (stochastic gradient descent)
梯度下降算法在每次更新迴歸係數的時候都需要遍歷整個數據集(計算整個數據集的迴歸誤差),該方法對小數據集尚可。但當遇到有數十億樣本和成千上萬的特徵時,就有點力不從心了,它的計算複雜度太高。改進的方法是一次僅用一個樣本點(的迴歸誤差)來更新迴歸係數。這個方法叫隨機梯度下降算法。由於可以在新的樣本到來的時候對分類器進行增量的更新(假設我們已經在數據庫A上訓練好一個分類器h了,那新來一個樣本x。對非增量學習算法來說,我們需要把x和數據庫A混在一起,組成新的數據庫B,再重新訓練新的分類器。但對增量學習算法,我們只需要用新樣本x來更新已有分類器h的參數即可),所以它屬於在線學習算法。與在線學習相對應,一次處理整個數據集的叫“批處理”。
隨機梯度下降算法的僞代碼如下:
###############################################
初始化迴歸係數爲1
重複下面步驟直到收斂{
對數據集中每個樣本
計算該樣本的梯度
使用alpha xgradient來更新迴歸係數
}
返回迴歸係數值
###############################################
2.3 改進的隨機梯度下降
1)在每次迭代時,調整更新步長alpha的值。隨着迭代的進行,alpha越來越小,這會緩解係數的高頻波動(也就是每次迭代係數改變得太大,跳的跨度太大)。當然了,爲了避免alpha隨着迭代不斷減小到接近於0(這時候,係數幾乎沒有調整,那麼迭代也沒有意義了),我們約束alpha一定大於一個稍微大點的常數項,具體見代碼。
2)每次迭代,改變樣本的優化順序。也就是隨機選擇樣本來更新迴歸係數。這樣做可以減少週期性的波動,因爲樣本順序的改變,使得每次迭代不再形成週期性。
改進的隨機梯度下降算法的僞代碼如下:
################################################
初始化迴歸係數爲1
重複下面步驟直到收斂{
對隨機遍歷的數據集中的每個樣本
隨着迭代的逐漸進行,減小alpha的值
計算該樣本的梯度
使用alpha x gradient來更新迴歸係數
}
返回迴歸係數值
2.4 批量梯度下降
其實批量的梯度下降就是一種折中的方法,他用了一些小樣本來近似全部的,其本質就是我1個指不定不太準,那我用個30個50個樣本那比隨機的要準不少了吧,而且批量的話還是非常可以反映樣本的一個分佈情況的。
#################################################
import random
# matrix_A 訓練集
matrix_A = [[1,4], [2,5], [5,1], [4,2]]
Matrix_y = [19,26,19,20]
theta = [2,4]
#學習速率
leraing_rate = 0.005
loss = 50
iters = 1
Eps = 0.0001
#隨機梯度下降
while loss>Eps and iters <1000 :
loss = 0
i = random.randint(0, 3)
h = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1]
theta[0] = theta[0] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][0]
theta[1] = theta[1] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][1]
Error = 0
Error = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1] - Matrix_y[i]
Error = Error*Error
loss = loss +Error
iters = iters +1
print ('theta=',theta)
print ('iters=',iters)
"""
#梯度下降
while loss>Eps and iters <1000 :
loss = 0
for i in range(4):
h = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1]
theta[0] = theta[0] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][0]
theta[1] = theta[1] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][1]
for i in range(4):
Error = 0
Error = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1] - Matrix_y[i]
Error = Error*Error
loss = loss +Error
iters = iters +1
print ('theta=',theta)
print ('iters=',iters)
"""
"""
#批量梯度下降
while loss>Eps and iters <1000 :
loss = 0
sampleindex = random.sample([0,1,2,3],2)
for i in sampleindex :
h = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1]
theta[0] = theta[0] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][0]
theta[1] = theta[1] + leraing_rate*(Matrix_y[i]-h)*matrix_A[i][1]
for i in sampleindex :
Error = 0
Error = theta[0]*matrix_A[i][0] + theta[1]*matrix_A[i][1] - Matrix_y[i]
Error = Error*Error
loss = loss +Error
iters = iters +1
print ('theta=',theta)
print ('iters=',iters)
"""