快速瞭解Logistic Regression原理及實踐

 一、Logistic Regression 算法

Logistic Regression  算法具有複雜度低、容易實現的優點,我們可以利用 Logistic Regression 算法實現廣告的點擊率估計。Logistic Regression 模型是線性的分類的模型,所謂線性通俗的來說只需要一條直線就可以將不同的類區分開來。這條直線也成爲超平面,使用

                                                                              Wx+b=0

表示,其中W爲權重,b爲偏置。

在 Logistic Regression 算法中對樣本進行分類,可以通過對訓練樣本的學習得到超平面,是數據分爲正負兩個類別。也可以使用閾值函數如 Sigmoid,將樣本映射到不同的類別中。

二、Sigmoid 函數

Sigmoid 函數的形式:

                                                   f\left ( x \right )=\frac{1}{1+e^{-x}}

Sigmoid 函數的基本性質:

  1. 定義域:(−∞,+∞)
  2. 值域:(−1,1)
  3. 函數在定義域內爲連續和光滑函數
  4. 處處可導,導數爲:f′(x)=f(x)(1−f(x))

Python 實現 Sigmoid 函數如下:

import matplotlib.pyplot as plt

import numpy as np

def  sigmoid(x):

    return 1.0 / (1.0 + np.exp(-x))

x = np.linspace(-10,10)

y = sigmoid(x)

plt.plot(x,y,label="Sigmoid",color = "blue")

plt.legend()

三、那爲什麼使用 Sigmoid ? 有如下兩種解釋

(一)Logistic Regression 算法的需求

Logistic Regression 算法中屬於正例即輸入向量 X 的概率爲 :

                                                          P(y=1|x,w,b)=Sigmoid(Wx+b)

負例的概率爲 :

                                                            P(y=0|x,w,b)=1-P(y=1|x,w,b)

對於一個有效的分類器,Wx+b ( w 和 x 的內積)代表了數據 x 屬於正類(y=1)的置信度。Wx+b 越大,這個數據屬於正類的可能性越大, Wx+b 越小,屬於反類的可能性越大。而 Sigmoid 函數恰好能夠將 Wx+b 映射到條件概率P(y=1|x,w,b) 上。Sigmoid 函數的值域是(0,1),滿足概率的要求,同時它是一個單調上升函數。最終, P(y=1|x,w,b)=Sigmoid(Wx+b),sigmoid的這些良好性質恰好能滿足 Logistic Regression 的需求。

(二)Sigmoid 函數和正態分佈函數的積分形式形狀非常類似。但計算正態分佈的積分函數,計算代價非常大,而Sigmoid由於其公式簡單,計算量非常的小。總之是 Sigmoid 函數能滿足分類任務,至於其他的也不要糾結,很多人都在用就不要苦惱了。

四、求參數W和b

   爲求參數 W 和 b, 使用極大似然法,通常使用 Log 似然函數的極大值求解參數,在 Logistic Regression 中將負的 Log 似然函數作爲損失函數 l_{W,b}

我們一般使用均方誤差來衡量損失函數,但考慮均方誤差損失函數一般是非凸函數,其在使用梯度下降算法的時候,容易得到局部最優解,不是全局最優解, 如下圖所示:

                                     非凸函數                                                                                    凸函數

所以要選擇凸函數,再者使用均方誤差其偏導值在輸出概率值接近0或者接近1的時候非常小,這可能會造成模型剛開始訓練時,偏導值幾乎消失,所以 Logistic Regression 算法選擇交叉熵損失函數。

定義如下:

假設訓練數據有 m 個訓練樣本,\small \left \{ \left ( X^{1} \right ,Y^{1}) ,(X^{2},Y^{2})\right ,...,\left ( X^{m} \right ,Y^{m})\},則損失函數爲:

                   \small l_{W,b}=-\frac{1}{m}\sum_{i=1}^{m}\left [ y^{i}log(Sigmoid(Wx^{i}+b)) +\right (1-y^{i})log(1-Sigmoid(Wx^{i}+b))]

所以我們的問題變成:

                                                     min l_{W,b}

五、梯度下降法

理清之後我們使用梯度下降的優化算法對損失函數 l 進行優化,尋找最優的參數 W。梯度下降法是一種迭代型的算法,根據初始點在每一次迭代的工程中選擇下降方向,同時改變需要修改的參數。

梯度下降法的過程如下:

  1. 隨機選擇一個初始點
  2. 重複下面的步驟: 
  •  決定梯度下降的方向:\small d_{i}=-\frac{\partial }{\partial w}f\left ( w \right )\mid _{w_{i}}
  • 選擇步長a
  • 更新:\small w_{i+1}=w_{i}+\alpha \cdot d_{i}    

     3.  直到滿足終止條件                                                                                                                                        

梯度下降法的更新公式:

                                                  \small \small W_{j}=W_{j}-\alpha \bigtriangledown _{w_{j}}(l_{W,b})

                                      \small \bigtriangledown _{w_{j}}(l_{W,b})=-\frac{1}{m}\sum_{i=1}^{m}(y^{i}-Sigmoid(Wx^{i}+b))x_{j}^{i}

公式推導如下圖:

其中a爲步長,選擇太小會導致收斂速度很慢,選擇太大會直接跳過最優解,如下圖所示,所以步長的選擇至關重要,負的梯度方向爲下降方向。

 

六、 Logistic Regression 算法應用

# -*- coding: utf-8 -*-
from sklearn.datasets import load_iris

import matplotlib.pyplot as plt

import numpy as np

iris = load_iris()

data = iris.data

target = iris.target

X = data[0:100,[0,2]]

y = target[0:100]

label = np.array(y)

index_0 = np.where(label==0)

class logistic(object):

    def __init__(self):

        self.W = None

    def train(self,X,y,learn_rate = 0.01,num_iters = 5000):

        num_train,num_feature = X.shape

        #init the weight

        self.W = 0.001*np.random.randn(num_feature,1).reshape((-1,1))

        loss = []       

        for i in range(num_iters):

            error,dW = self.compute_loss(X,y)

            self.W += -learn_rate*dW

            loss.append(error)

        return loss  

    def compute_loss(self,X,y):

        num_train = X.shape[0]

        h = self.output(X)

        loss = -np.sum((y*np.log(h) + (1-y)*np.log((1-h))))

        loss = loss / num_train

        dW = X.T.dot((h-y)) / num_train

        return loss,dW

    def output(self,X):

        g = np.dot(X,self.W)

        return self.sigmod(g)

    def sigmod(self,X):

        return 1/(1+np.exp(-X))

    def predict(self,X_test):

        h = self.output(X_test)

        y_pred = np.where(h>=0.5,1,0)

        return y_pred
 
y = y.reshape((-1,1))

#add the x0=1

one = np.ones((X.shape[0],1))

X_train = np.hstack((one,X))

classify = logistic()

loss = classify.train(X_train,y)

plt.plot(loss)

plt.xlabel('Iteration number')

plt.ylabel('Loss value')

plt.show()

label = np.array(y)

index_0 = np.where(label==0)

plt.scatter(X[index_0,0],X[index_0,1],marker='x',color = 'y',label = '0',s = 12)

index_1 =np.where(label==1)

plt.scatter(X[index_1,0],X[index_1,1],marker='o',color = 'b',label = '1',s = 12)

x1 = np.arange(4,7.5,0.5)

x2 = (- classify.W[0] - classify.W[1]*x1) / classify.W[2]

plt.plot(x1,x2,color = 'black')

plt.xlabel('X1')

plt.ylabel('X2')

plt.legend(loc = 'upper left')

plt.show()

參考文獻:

趙志勇《Python 機器學習算法》

Coursera機器學習課程

 

 

 

 

 

 

 

 

 

 

 

 

 

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