05 Logistic Regression

1 Logistic 原理

邏輯迴歸從字面上看是一個迴歸問題,很容易和迴歸分析聯繫到一起。這是字面意思給人的錯覺,其實它不是迴歸問題!它是最典型的分類問題,經典的二分類,比如檢查郵件是否是垃圾郵件,檢查一個零件是否是合格件,判斷一個西瓜是否成熟等等,這些日常生活中經常用於判斷是非黑白的問題,都能用到這個經典的二分類之邏輯迴歸。如下圖:
在這裏插入圖片描述
這樣一個線性可分的問題,需要這麼一個超平面將其分開。而邏輯迴歸,使用閾值函數,將樣本映射到不同類別中。常用的映射函數爲Sigmoid函數形式如下:
f(x)=11+exf(x)=\frac{1}{1+e^{-x}} 它的圖像如下:
在這裏插入圖片描述
從圖像可以看出,其函數值值域在(0,1),在 0 附近的變化較爲明顯。其導數爲:
f(x)=ex(1+ex)2=f(x)[1f(x)]f'(x)=\frac{e^{-x}}{(1+e^{-x})^2}=f(x)[1-f(x)]
對於線性迴歸模型:hθ(x)=θTxh_\theta(x)=\theta^T x
將線性模型帶入到g(x)中,得到最終的邏輯迴歸模型:
hθ(x)=g(θTx)=11+eθTxh_\theta(x)=g(\theta^T x)=\frac{1}{1+e^{-\theta^T x}}
對於輸入向量X,其屬於正例的概率:
P(y=1X;θ)=hθ(x)P(y=1|X;\theta)=h_\theta(x)
對於輸入向量X,其屬於負例的概率爲:
P(y=0X;θ)=1hθ(x)P(y=0|X;\theta)=1-h_\theta(x)

整合起來,就是其屬於類別c的概率爲:
P(y=cX;θ)=(hθ(x))y(1hθ(x))yP(y=c|X;\theta)=(h_\theta(x))^y(1-h_\theta(x))^y

要求參數,方法與線性迴歸一樣,先求出由所有樣本組成的似然函數,轉化爲對數似然,轉化爲梯度下降,根據梯度下降的方向更新迭代權重參數,選取代價函數本次與上次的差小於某個閾值的迭代思路求解。
其中,似然函數爲,m表示樣本個數
L(θ)=i=1m(hθ(x))y(1hθ(x))1yL(\theta)= \prod_{i=1}^m (h_\theta(x))^y(1-h_\theta(x))^{1-y} \quad
對數似然函數:
log(L(θ))=i=1my(hθ(x))+(1y)(1hθ(x))log(L(\theta))= \sum_{i=1}^m y(h_\theta(x))+(1-y)(1-h_\theta(x)) \quad
然後,利用對數極大似然估計,即求上式的極大值,引入因子 -1/m,轉化爲求下式的極小值:
J(θ)=1mlog(L(θ))J(\theta)=-\frac{1}{m}log(L(\theta))
對上式求偏導後的結果如下,在此不一 一詳細寫出推導過程了,但是說明下式的參數含義,其中θj\theta_j表示第i個樣本的第j個特徵的權重參數,注意如果有100個特徵,自然地就有100個權重參數,等號左邊是對θj\theta_j求偏導的,因此這個式子相當於對某個樣本的所有特徵參數都適應於下面的公式。
θjJ(θ)=1mi=1m(hθ(x)yi)θij\frac{∂}{∂\theta_j}J(\theta)=\frac{1}{m}\sum_{i=1}^m (h_\theta(x)-y_i)\theta_i^j

2 代碼

先生成第一張圖的數據,也就是實驗數據。然後使用梯度下降法求出倆個特徵對應的權重參數。

設定一個學習率迭代參數,當與前一時步的代價函數與當前的代價函數的差小於閾值時,計算結束,我們將得到3個權重參數,其中包括兩個特徵的權重參數,和偏置項的權重參數。
梯度下降求邏輯迴歸模型的權重參數的基本思路如下:

  1. ‘model’ 建立的邏輯迴歸模型:包括Sigmoid映射, 也就是上面的 hθ(x)h_\theta(x)
  2. ‘cost’ 代價函數,也就是上訴的J(θ)J(\theta)
  3. ‘gradient’ 梯度公式,也就是上訴的θjJ(θ)\frac{∂}{∂\theta_j}J(\theta)
  4. ‘theta update’ 參數更新公式
  5. ‘stop stratege’ 迭代停止策略:代價函數小於閾值法
#!/user/bin/env python
#-*- coding:utf-8 -*-
#by: LiuWei
"""邏輯斯提克迴歸"""
import numpy as np
import matplotlib.pyplot as plt
import time

#按照一定規律均勻分佈含有兩個特徵的數據點
def createData(samplecnt,coef=1.0,intercept=0.05):
    x1 = np.random.uniform(0,1,samplecnt)
    x2 = np.random.uniform(0,1,samplecnt)
    index = (x2-intercept)/x1 <coef
    x1_pos = x1[index]
    x2_pos = x2[index]
    index = (x2-intercept)/x1 >=coef
    x1_neg = x1[index]
    x2_neg = x2[index]
    plt.xlabel("w1")
    plt.ylabel("w2")
    plt.scatter(x1_pos,x2_pos)
    plt.scatter(x1_neg,x2_neg)
    regx = np.linspace(0,1,samplecnt)
    regy = coef*regx+intercept
    #plt.plot(regx,regy,color='g')
    plt.show()
    return x1_pos,x1_neg,x2_pos,x2_neg

#組合成原始數據
def combine_data(x1_pos,x1_neg,x2_pos,x2_neg):
    x1_pos_1 = x1_pos.reshape(-1,1)
    x2_pos_1 = x2_pos.reshape(-1,1)
    x_pos = np.concatenate((x1_pos_1,x2_pos_1),axis=1)
    x_pos_shape =  np.shape(x_pos)
    y_pos = np.ones(x_pos_shape[0])
    y_pos = y_pos.reshape(-1,1)
    data_pos = np.concatenate((x_pos,y_pos),axis=1)
    x1_neg_1 = x1_neg.reshape(-1,1)
    x2_neg_1 = x2_neg.reshape(-1,1)
    x_neg = np.concatenate((x1_neg_1,x2_neg_1),axis=1)
    x_neg_shape = np.shape(x_neg)
    y_neg = np.zeros(x_neg_shape[0])
    y_neg = y_neg.reshape(-1,1)
    data_neg = np.concatenate((x_neg,y_neg),axis=1)
    data = np.vstack((data_pos,data_neg))
    data = np.random.permutation(data)
    return data

#生成數據
x1_pos,x1_neg,x2_pos,x2_neg=createData(200)
data=combine_data(x1_pos,x1_neg,x2_pos,x2_neg)
# print(data[:10,:])
X = data[:,:2]
y = data[:,-1]

#偏移量 b shape=(200,1)
b = np.ones(200)
#將偏移量與2個特徵值組合 shape = (200,3)
X = np.column_stack((b,X))

# #model 
def sigmoid(x):
    return 1/(1+ np.exp(-x))
def model(theta,X):
    theta = np.array(theta)
    return sigmoid( X.dot(theta) )

#cost
def cost(m,theta,X,y):
    ele = y*np.log(model(theta,X)) + (1-y)*np.log(1-model(theta,X))
    item_sum = np.sum(ele)
    return -item_sum/m

#gradient
def gradient(m,theta,X,y,cols):
    grad_theta = []
    for j in range(cols):
        grad = (model(theta,X) - y).dot(X[:,j])
        grad_sum = np.sum(grad)
        grad_theta.append(grad_sum/m)
    return np.array(grad_theta)

#theta update
def theta_update(grad_theta,theta,sigma):
    return theta - sigma * grad_theta

#stop stratege
def stop_stratege(cost,cost_update,threshold):
    return cost-cost_update < threshold

#邏輯迴歸算法
def LogicRegression(X,y,threshold,m,xcols):
    start = time.clock()
    #設置權重參數的初始值
    theta = np.zeros(xcols)
    #迭代步數
    iters = 0
    #記錄代價函數的值
    cost_record=[]
    #學習率
    sigma = 0.01
    cost_val = cost(m,theta,X,y)
    cost_record.append(cost_val)
    while True:
        grad = gradient(m,theta,X,y,xcols)
        #參數更新
        theta = theta_update(grad,theta,sigma)
        cost_update = cost(m,theta,X,y)
        if stop_stratege(cost_val,cost_update,threshold):
            break
        iters=iters+1
        cost_val = cost_update
##        print("cost_val:%f" %cost_val)
        cost_record.append(cost_val)
    end = time.clock()
    print("LogicRegressionconvergence duration: %f s" % (end - start))
    return cost_record, iters,theta

cost_record, iters,theta= LogicRegression(X,y,1e-7,200,3)#調用邏輯迴歸函數
plt.scatter(x1_pos,x2_pos)
plt.scatter(x1_neg,x2_neg)
wp = np.linspace(0.0,1.0,200)
plt.plot(wp,-(theta[0]+theta[1]*wp)/theta[2],color='g')
plt.show()

調用函數,收斂時得到的權重爲:

array([  1.4441927 ,  17.07777938, -17.26372013])

在這裏插入圖片描述
參數的含義:第一個權重參數爲偏置項,第二、三個權重參數相當,只不過貢獻方向相反而已。

畫出決策面如下:
在這裏插入圖片描述
效果還不錯!

總結

  1. 如果代價函數的最後穩定的值,確認比較大,比如0.5,說明模型中一定存在某些bug,比如在調試過程中,將標籤值錯誤地被賦值了第三列,實際應該爲第四列,所以導致最後迭代終止時的成本值爲0.50。
  2. 學習率直接關係到迭代速度,如果學習率太小,迭代下降的會很慢,相反會比較快。
  3. 迭代終止的策略選取,一般會根據迭代次數,成本函數前後兩次的差小於某個閾值等,如果選取的終止策略不當,會導致看似收斂,實際成本值還很大的情況。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章