邏輯迴歸(LR)公式推導及代碼實現

邏輯迴歸是用來解決分類問題用的,與線性迴歸不同的是,邏輯迴歸輸出的不是具體的值,而是一個概率。除去了sigmoid函數的邏輯歸回和線性迴歸幾乎是一樣的。

構造hypothesis

邏輯迴歸的HH可以看做是一個線性迴歸方程的結果經過一個sigmoid函數得到的結果(爲正樣本的概率),邏輯迴歸的假設函數如下:
hθ(x)=g(θTx)=11+eθTx h _ { \theta } ( x ) = g \left( \theta ^ { T } x \right) = \frac { 1 } { 1 + e ^ { - \theta ^ { T } x } }

函數 hθ(x)h _ { \theta } ( x ) 表示樣本被預測爲正例 11 的概率,我們很容易的得到樣本被預測爲正例和負例的概率如下:
P(y=1x; θ)=hθ(x)P(y=0x; θ)=1hθ(x) \begin{array} { l } P ( y = 1 | x ;\ \theta ) = h_{\theta} ( x ) \\ P ( y = 0 | x ; \ \theta ) = 1 - h _ { \theta } ( x ) \end{array}

上式可以合併爲一個式子:(預測結果的概率表示)
P(yx;θ)=(hθ(x))y(1hθ(x))1y P ( y | x ; \theta ) = \left( h _ { \theta } ( x ) \right) ^ { y } \left( 1 - h _ { \theta } ( x ) \right) ^ { 1 - y }

構造損失函數

我們對“預測結果的概率表示”取似然函數,取似然函數就是將模型對樣本的概率預測值累乘起來。得到如下的似然函數
L(θ)=i=1mP(y(i)x(i);θ)=i=1m(hθ(x(i)))y(i)(1hθ(x(i)))1y(i) L ( \theta ) = \prod _ { i = 1 } ^ { m } P \left( y ^ { ( i ) } | x ^ { ( i ) } ; \theta \right) = \prod _ { i = 1 } ^ { m } \left( h _ { \theta } \left( x ^ { ( i ) } \right) \right) ^ { y ^ { ( i ) } } \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) ^ { 1 - y ^ { ( i ) } }

由於該式比較麻煩涉及連乘法,所以我們對其去加對數操作得到對數似然函數

上述利用的是最大似然估計原理:極大似然估計就是利用已知的樣本分佈,找到最有可能(即最大概率)導致這種分佈的參數值;或者說什麼樣的參數才能使我們觀測到目前這組數據的概率最大。
l(θ)=logL(θ)=i=1m(y(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))) l ( \theta ) = \log L ( \theta ) = \sum _ { i = 1 } ^ { m } \left( y ^ { ( i ) } \log h _ { \theta } \left( x ^ { ( i ) } \right) + \left( 1 - y ^ { ( i ) } \right) \log \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) \right)

當似然函數求得最大值時,模型參數能夠最大可能的滿足當前的樣本,求最大值使用梯度向上法,我們可以對似然函數加個負號,通過求等價問題的最小值來求原問題的最大值,這樣我們就可以使用極大似然估計法。(注意這裏還多加了個1m\frac { 1 } { m }
J(θ)=1ml(θ) J ( \theta ) = - \frac { 1 } { m } l ( \theta )

這樣我們就能得到損失函數的最終形式
J(θ)=1mi=1m(y(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))) J ( \theta ) = - \frac { 1 } { m } \sum _ { i = 1 } ^ { m } \left( y ^ { ( i ) } \log h _ { \theta } \left( x ^ { ( i ) } \right) + \left( 1 - y ^ { ( i ) } \right) \log \left( 1 - h _ { \theta } \left( x ^ { ( i ) } \right) \right) \right)

即等價於:
cost(hθ(x), y)={log(hθ(x)) if y=1log(1hθ(x)) if y=0 \operatorname { cost } ( h _ { \theta } ( x ) ,\ y ) = \left\{ \begin{array} { l l } - \log \left( h _ { \theta } ( x ) \right) & \text { if } y = 1 \\ - \log \left( 1 - h _ { \theta } ( x ) \right) & \text { if } y = 0 \end{array} \right.

通過“梯度下降法”求參數 θ\theta 的更新式

我們下圖爲推導式,面試推導的時候可以不寫下標(假設我們使用隨機梯度下降法),這樣可以使推導式更簡潔。

求梯度
在這裏插入圖片描述
這裏需要提一下的是,sigmoid函數有如下性質,在上述推導的第三行中可以看到:
S(x)=ex(1+ex)2=S(x)(1S(x)) S ^ { \prime } ( x ) = \frac { e ^ { - x } } { \left( 1 + e ^ { - x } \right) ^ { 2 } } = S ( x ) ( 1 - S ( x ) )

θ更新式:α 爲學習率
θj:=θjα1mi=1m(hθ(x(i))y(i))xj(i) \theta _ { j } : = \theta _ { j } - \alpha \frac { 1 } { m } \sum _ { i = 1 } ^ { m } \left( h _ { \theta } \left( x ^ { ( i ) } \right) - y ^ { ( i ) } \right) x _ { j } ^ { ( i ) }

總結:LR在確定了模型的形式後,通過最大似然估計法來實現最小散度從而求出模型參數。

代碼實現

向量化:向量化是使用矩陣計算來代替for循環,以簡化計算過程,提高效率。

# -*- coding: utf-8 -*-
from numpy import *
from matplotlib import pyplot as plt


def plot_best_fit(wei, data_set, label):
    weights = wei
    data_set = array(data_set)
    n = shape(data_set)[0]
    xcourd1 = []; ycourd1 = []
    xcourd2 = []; ycourd2 = []
    for i in range(n):
        if int(label[i]) == 1:
            xcourd1.append(data_set[i, 1]); ycourd1.append(data_set[i, 2])
        else:
            xcourd2.append(data_set[i, 1]); ycourd2.append(data_set[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcourd1, ycourd1, s=30, c='red', marker='s')
    ax.scatter(xcourd2, ycourd2, s=30, c='green')
    x = arange(-3.0, 3.0, 0.1)
    y = (-weights[0] - weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2')
    plt.show()

def load_data():
    data_set = []
    label = []
    fr = open('./text.txt')
    for line in fr.readlines():
        line = line.strip().split()
        data_set.append([1.0, float(line[0]), float(line[1])])
        label.append(int(line[2]))
    return data_set, label


def sigmoid(x):
    return 1.0 / (1 + exp(-x))

# 梯度下降算法               GD
def train(data_set, label):
    data_matrix = mat(data_set)
    label = mat(label).transpose()
    m, n = shape(data_matrix)
    alpha = 0.001
    max_cycles = 500
    weights = ones((n, 1))
    for k in range(max_cycles):
        h = sigmoid(data_matrix*weights)
        error = h - label
        weights = weights - alpha * data_matrix.transpose() * error
    return weights

# on line to study         SGD
def stoc_grad_descent(data_set, label):
    m, n = shape(data_set)
    alpha = 0.01
    weights = ones(n)
    for i in range(m):
        h = sigmoid(sum(data_set[i]*weights))
        error = h - label[i]
        weights = weights - alpha * error * data_set[i]
    return weights

# on line to study prove
def prove_grad_ascent(data_set, label, num_iter=450):
    m, n = shape(data_set)
    weights = ones(n)
    for j in range(num_iter):
        data_index = range(m)
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.01    # prevent swings
            # choose a random value to prevent periodic swings
            rand_index = int(random.uniform(0, len(data_index)))
            h = sigmoid(sum(data_set[rand_index]*weights))
            error = label[rand_index] - h
            weights = weights + alpha * error * data_set[rand_index]
            del data_index[rand_index]
    return weights

if __name__ == "__main__":
    data_set, label = load_data()
    #print label
    #weights = train(array(data_set), label)
    #weights = stoc_grad_ascent(array(data_set), label)
    weights = prove_grad_ascent(array(data_set), label)
    plot_best_fit(weights, data_set, label)

References

  • https://blog.csdn.net/dpengwang/article/details/86746233
  • https://www.jianshu.com/p/471b2fd570a3
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章