邏輯回歸

邏輯回歸
邏輯回歸是一種經(jīng)典的二分類算法,它的決策邊界可以是非線性的(包含高階項(xiàng))
Sigmoid函數(shù)
公式:g(z)=\frac{1}{1+{{e}^{-z}}}柿扣,其中自變量取值為任意實(shí)數(shù)
解釋:將任意的輸入映射到了[0,1]區(qū)間
比如在線性回歸中可以得到一個(gè)預(yù)測值(\hat{y})肖方,再將該值映射到Sigmoid函數(shù),就完成了由值到概率的轉(zhuǎn)換未状,也就是分類任務(wù)
假設(shè)預(yù)測函數(shù){{h}_{\mathbf{\theta }}}(x)=g({{\mathbf{\theta }}^{\mathbf{T}}}\mathbf{X})=\frac{1}{1+{{e}^{-{{\mathbf{\theta }}^{\mathbf{T}}}\mathbf{X}}}}
分類任務(wù):\begin{align} & p(y=1|\mathbf{X};\mathbf{\theta })={{h}_{\mathbf{\theta }}}(x) \\ & p(y=0|\mathbf{X};\mathbf{\theta })=1-{{h}_{\mathbf{\theta }}}(x) \\ \end{align}
相當(dāng)于0-1分布俯画,整合上述式子得p(y|\mathbf{X};\mathbf{\theta })={{({{h}_{\mathbf{\theta }}}(x))}^{y}}{{(1-{{h}_{\mathbf{\theta }}}(x))}^{1-y}}
似然函數(shù):
L(\mathbf{\theta })=\prod\limits_{i=1}^{m}{p(y|\mathbf{X};\mathbf{\theta })}=\prod\limits_{i=1}^{m}{{{({{h}_{\mathbf{\theta }}}({{x}_{i}}))}^{{{y}_{i}}}}{{(1-{{h}_{\mathbf{\theta }}}({{x}_{i}}))}^{1-{{y}_{i}}}}}
取對數(shù)似然函數(shù):
\ln L(\mathbf{\theta })=\sum\limits_{i=1}^{m}{{{y}_{i}}\ln ({{h}_{\theta }}({{x}_{i}}))\text{+(1-}}{{y}_{i}})\ln (1-{{h}_{\theta }}({{x}_{i}}))
現(xiàn)在要求上述對數(shù)似然函數(shù)的最大值,如果要用梯度下降法司草,需要將目標(biāo)函數(shù)轉(zhuǎn)化為求最小值【梯度的方向是值越來越大的方向艰垂,求最小值,應(yīng)該朝著梯度反方向走】埋虹,因此引入
J(\mathbf{\theta })=-\frac{1}{m}\ln L(\mathbf{\theta })=-\frac{1}{m}\sum\limits_{i=1}^{m}{{{y}_{i}}\ln ({{h}_{\theta }}({{x}_{i}}))\text{+(1-}}{{y}_{i}})\ln (1-{{h}_{\theta }}({{x}_{i}}))
對上式求偏導(dǎo)
\begin{align} & \frac{\partial J(\mathbf{\theta })}{\partial {{\theta }_{j}}}=-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}\frac{1}{{{h}_{\mathbf{\theta }}}({{x}_{i}})}\frac{\partial {{h}_{\mathbf{\theta }}}({{x}_{i}})}{\partial {{\theta }_{j}}}-(1-{{y}_{i}})\frac{1}{1-{{h}_{\mathbf{\theta }}}({{x}_{i}})}\frac{\partial {{h}_{\mathbf{\theta }}}({{x}_{i}})}{\partial {{\theta }_{j}}} \right]} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}\frac{1}{{{h}_{\mathbf{\theta }}}({{x}_{i}})}-(1-{{y}_{i}})\frac{1}{1-{{h}_{\mathbf{\theta }}}({{x}_{i}})} \right]}\frac{\partial {{h}_{\mathbf{\theta }}}({{x}_{i}})}{\partial {{\theta }_{j}}} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}\frac{1}{g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})}-(1-{{y}_{i}})\frac{1}{1-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})} \right]}\frac{\partial g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})}{\partial {{\theta }_{j}}} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}\frac{1}{g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})}-(1-{{y}_{i}})\frac{1}{1-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})} \right]}\frac{{{e}^{-{{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{\mathbf{i}}}}}}{1+{{e}^{-{{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{\mathbf{i}}}}}}x_{i}^{j} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}\frac{1}{g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})}-(1-{{y}_{i}})\frac{1}{1-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})} \right]}g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}})(1-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}}))x_{i}^{j} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}(1-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}}))-(1-{{y}_{i}})g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}}) \right]}x_{i}^{j} \\ & \text{ =}-\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{y}_{i}}-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}}) \right]}x_{i}^{j} \\ & \text{ =}\frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{h}_{\mathbf{\theta }}}({{x}_{i}})-{{y}_{i}} \right]}x_{i}^{j} \\ \end{align}
確定了梯度方向之后驹马,利用上式更新參數(shù)秩冈,得到
\theta _{j}^{'}={{\theta }_{j}}-\alpha \frac{1}{m}\sum\limits_{i=1}^{m}{\left[ {{h}_{\mathbf{\theta }}}({{x}_{i}})-{{y}_{i}} \right]}x_{i}^{j}
按照上式繼續(xù)迭代
下面是一個(gè)關(guān)于實(shí)現(xiàn)邏輯回歸的小例子
目標(biāo):建立一個(gè)邏輯回歸模型來預(yù)測一個(gè)大學(xué)生是否被大學(xué)錄取潜腻。
特征:兩次考試成績
導(dǎo)入數(shù)據(jù)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pdData=pd.read_csv('C:/Users/lenovo/Desktop/LogiReg_data.txt',header=None,names=['Exam 1','Exam 2','Admitted'])#header=None不讓數(shù)據(jù)自己指定列名
pdData.insert(0,'ones',1) #為了考慮常數(shù)項(xiàng)
pdData.head()

數(shù)據(jù)如以下所示


image.png

通常在做數(shù)據(jù)處理之前遂铡,需要做一些數(shù)據(jù)預(yù)處理,比如數(shù)據(jù)標(biāo)準(zhǔn)化等辣辫,這邊先不做旦事,看看不做標(biāo)準(zhǔn)化會對結(jié)果什么影響。
邏輯回歸的關(guān)鍵是計(jì)算損失值和梯度方向
為了計(jì)算這兩個(gè)函數(shù)急灭,需要引入sigmoid函數(shù)【將值映射到概率】

#定義sigmoid函數(shù)
def sigmoid_2(z):
    return 1/(1+np.exp(-z))
#預(yù)測函數(shù)模型
def model(X,theta):
    return sigmoid_2(np.dot(X,theta.T))

切片姐浮,分出X和y

orig_data=pdData.as_matrix()# 轉(zhuǎn)換成array類型
cols=orig_data.shape[1]
X=orig_data[:,:cols-1]#前三列,切片012
y=orig_data[:,cols-1:]#和y=orig_data[:,cols-1]結(jié)果額維度不一樣
theta=np.zeros([1,3]) #theta初始化是0

注:這里要注意一個(gè)關(guān)于數(shù)組切片的問題


image.png

上面畫圈的兩個(gè)語句一個(gè)返回一維數(shù)組,一個(gè)返回三維數(shù)組

損失函數(shù)

將對數(shù)似然函數(shù)取相反數(shù)
-\ln L(\mathbf{\theta })=-\sum\limits_{i=1}^{n}{{{y}_{i}}\ln ({{h}_{\theta }}({{x}_{i}}))-\text{(1-}}{{y}_{i}})\ln (1-{{h}_{\theta }}({{x}_{i}}))
求平均損失
J(\mathbf{\theta })=\frac{1}{n}\ln L(\mathbf{\theta })=\frac{1}{n}\sum\limits_{i=1}^{n}{\text{-}{{y}_{i}}\ln ({{h}_{\theta }}({{x}_{i}}))\text{-(1-}}{{y}_{i}})\ln (1-{{h}_{\theta }}({{x}_{i}}))
目的是求平均損失的最小值

def cost(X,y,theta):#對應(yīng)于J(theta)
    left=np.multiply(-y,np.log(model(X,theta)))#np.multiply對應(yīng)位置相乘
    right=np.multiply(1-y,np.log(1-model(X,theta)))
    return np.sum(left-right)/len(X)

計(jì)算梯度

\frac{\partial J(\mathbf{\theta })}{\partial {{\theta }_{j}}}\text{=}-\frac{1}{n}\sum\limits_{i=1}^{n}{\left[ {{y}_{i}}-g({{\mathbf{\theta }}^{\mathbf{T}}}{{\mathbf{x}}_{i}}) \right]}x_{i}^{j}\text{=}\frac{1}{n}\sum\limits_{i=1}^{n}{\left[ {{h}_{\mathbf{\theta }}}({{x}_{i}})-{{y}_{i}} \right]}x_{i}^{j}

def gradient(X,y,theta):
    grad=np.zeros(theta.shape)
    error=(model(X,theta)-y).ravel()
   # print(error.shape)
    for j in range(len(theta.ravel())):#求每個(gè)參數(shù)的偏導(dǎo)
        term=np.multiply(error,X[:,j])
        grad[0,j]=np.sum(term)/len(X)
    return grad

參數(shù)更新

首先設(shè)定三種停止策略【迭代次數(shù)葬馋、損失值差距卖鲤、梯度】

def stopCriterion(type,value,threshold):
    if type==STOP_ITER:
        return value>threshold #返回邏輯值#迭代次數(shù)
    elif type==STOP_COST:
        return abs(value[-1]-value[-2])<threshold#兩次迭代結(jié)果的損失值差距較小
    elif type==STOP_GRAD:
        return np.linalg.norm(value)<threshold #梯度較小

為了避免原數(shù)據(jù)存在某種規(guī)律【比如先收集女生成績再收集男生成績】,將原數(shù)據(jù)順序打亂

import numpy.random
#洗牌畴嘶,將數(shù)據(jù)順序打亂
def shuffleData(data):
    np.random.shuffle(data)  #shuffle() 方法將序列的所有元素隨機(jī)排序
    cols=data.shape[1]
    X=data[:,:cols-1]
    y=data[:,cols-1:]
    return X,y

然后進(jìn)行參數(shù)更新【引入time庫是為了比較不同策略的運(yùn)行時(shí)間】

import time
def descent(data,theta,batchSize,stopType,thresh,alpha):
    #batchSize等于總樣本數(shù)蛋逾,即批量梯度下降;batchSize等于1窗悯,即隨機(jī)梯度下降区匣;batchSize取1~n之間的數(shù)據(jù),即小批量梯度下降
    
    
    #梯度下降求解
    #初始化
    init_time=time.time()  #比較不同梯度下降方法的運(yùn)行速度
    i=0 #迭代次數(shù)蒋院,第0次開始
    k=0 #batch
    X,y=shuffleData(data)
    grad=np.zeros(theta.shape)  #計(jì)算的梯度
    costs=[cost(X,y,theta)]  #計(jì)算損失值
    
    
    
    while True:
        grad=gradient(X[k:k+batchSize],y[k:k+batchSize],theta)
        k += batchSize #取樣本數(shù)據(jù)
        if k >= n:
            k = 0
            X,y=shuffleData(data) #重新洗牌
        theta = theta - alpha*grad  # 參數(shù)更新
        costs.append(cost(X,y,theta))
        i += 1
        
        #停止策略
        if stopType==STOP_ITER:
            value = i
        elif stopType==STOP_COST:
            value=costs
        elif stopType==STOP_GRAD:
            value=grad
        if stopCriterion(stopType,value,thresh):#如果if語句為真亏钩,就跳出整個(gè)循環(huán)
            break
        #print(grad,np.linalg.norm(grad))
    return theta,i-1,costs,grad,time.time()-init_time

注:np.linalg.norm([4,3])表示\sqrt{{{3}^{2}}+{{4}^{2}}}

def runExpe(data,theta,batchSize,stopType,thresh,alpha):
    theta,iter,costs,grad,dur=descent(data,theta,batchSize,stopType,thresh,alpha)
#     name='Original' if (data[:,2]>2).sum()>1 else 'Scaled'
#     name += 'data-learning rate: {} -'.format(alpha)
#     if batchSize==n: strDescType='Gradient'
#     elif batchSize==1: strDescType='Stochastic'
#     else:strDescType='mini-batch {} '.format(batchSize)
#     name += strDescType + 'descent-stop: '
#     if stopType==STOP_ITER: strStop='{} iterations'.format(thresh)
#     elif stopType==STOP_COST: strStop='cost change < {}'.format(thresh)
#     else: strStop ='gradient norm < {}'.format(thresh)
#     name += strStop
    fig,ax=plt.subplots(figsize=(12,4))
    ax.plot(np.arange(len(costs)),costs,c='r')
    ax.set_xlabel('Iteration')
    ax.set_ylabel('Cost')
    #ax.set_title(name.upper())
    print('iter: {}, last cost: {:03.2f}, duration: {:03.2f}s'.format(iter,costs[-1],dur))
    return theta

不同的停止策略

以批量梯度下降為例

  • 停止條件為迭代次數(shù)
n=100
runExpe(orig_data,theta,n,STOP_ITER,thresh=5000,alpha=0.000001)

返回


image.png

看似損失值已經(jīng)穩(wěn)定在最低點(diǎn)0.63

  • 停止條件為損失值
    設(shè)定閾值為0.000001,需要迭代110000次左右
runExpe(orig_data,theta,n,STOP_COST,thresh=0.000001,alpha=0.001)

返回


image.png

損失值最低為0.38欺旧,似乎還可以進(jìn)一步收斂

  • 停止條件為梯度大小
    設(shè)定閾值0.05姑丑,需要迭代40000次左右
runExpe(orig_data,theta,n,STOP_GRAD,thresh=0.05,alpha=0.001)

返回


image.png

損失值最小為0.49,似乎還可以進(jìn)一步收斂
綜上辞友,基于批量梯度下降方法栅哀,上述三種停止條件得到的損失函數(shù)值為0.63震肮、0.38和0.49,迭代次數(shù)分別為5000次留拾、110000次和40000次戳晌,迭代次數(shù)越多,損失值越小

對比不同的梯度下降方法

停止策略為迭代次數(shù)

  • 隨機(jī)梯度下降
runExpe(orig_data,theta,1,STOP_ITER,thresh=5000,alpha=0.001)

返回


image.png

波動非常大间驮,迭代過程不穩(wěn)定躬厌,這也是隨機(jī)梯度下降的主要缺點(diǎn)
嘗試降低學(xué)習(xí)率為0.000001马昨,增加迭代次數(shù)為15000

runExpe(orig_data,theta,1,STOP_ITER,thresh=15000,alpha=0.000001)

返回


image.png

效果要好一些竞帽,損失值似乎穩(wěn)定在0.63,根據(jù)上面的結(jié)果可知,0.63不算是一個(gè)特別合理的值

  • 小批量梯度下降
#取樣本為16
runExpe(orig_data,theta,16,STOP_ITER,thresh=15000,alpha=0.001)

返回


image.png

上下波動鸿捧,迭代過程不穩(wěn)定
嘗試調(diào)低學(xué)習(xí)率為0.000001

runExpe(orig_data,theta,16,STOP_ITER,thresh=15000,alpha=0.001)

返回


image.png

降低學(xué)習(xí)率之后沒有效果屹篓,迭代過程依舊不穩(wěn)定
因此,可能不是模型本身的問題匙奴,而是數(shù)據(jù)本身的問題堆巧,嘗試著對數(shù)據(jù)做一些變換,此處對數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化泼菌,用標(biāo)準(zhǔn)化后的數(shù)據(jù)求解

#標(biāo)準(zhǔn)化
from sklearn import preprocessing as pp
scaled_data=orig_data.copy()
scaled_data[:,1:3]=pp.scale(scaled_data[:,1:3])
#用標(biāo)準(zhǔn)化后的數(shù)據(jù)求解
runExpe(scaled_data,theta,16,STOP_ITER,thresh=15000,alpha=0.001)

返回


image.png

損失值收斂到0.28谍肤,比0.63好很多
再嘗試一下梯度為停止條件的情況

runExpe(scaled_data,theta,16,STOP_GRAD,thresh=0.004,alpha=0.001)

返回


image.png

迭代次數(shù)由15000增加到60000多,損失值由0.28降低到0.22哗伯,又改善了一步

計(jì)算模型分類結(jié)果的精確率

#設(shè)定閾值為0.5荒揣,大于0.5就可以入學(xué)
def predict(X,theta):
    return [1 if x >= 0.5 else 0 for x in model(X,theta)]
scaled_X=scaled_data[:,:3]
y=scaled_data[:,3]
theta = runExpe(scaled_data,theta,16,STOP_GRAD,thresh=0.004,alpha=0.001)
predictions = predict(scaled_X,theta)
correct = [1 if a==b else 0 for (a,b) in zip(predictions,y)]   #真實(shí)值與預(yù)測值相等,同為1或者同為0
accuracy = sum(correct)/len(correct)

返回accuracy等于0.89
通過這個(gè)例子焊刹,算是對邏輯回歸的基本原理有一個(gè)比較清晰的認(rèn)識了系任。

  • sigmoid函數(shù):將值映射到概率的函數(shù)
  • model:返回預(yù)測結(jié)果值
  • cost:根據(jù)參數(shù)計(jì)算損失
  • gradient:計(jì)算每個(gè)參數(shù)的梯度方向
  • descent:進(jìn)行每個(gè)參數(shù)的更新
  • accuracy:計(jì)算精度
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市虐块,隨后出現(xiàn)的幾起案子俩滥,更是在濱河造成了極大的恐慌,老刑警劉巖贺奠,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霜旧,死亡現(xiàn)場離奇詭異,居然都是意外死亡儡率,警方通過查閱死者的電腦和手機(jī)挂据,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喉悴,“玉大人棱貌,你說我怎么就攤上這事』啵” “怎么了婚脱?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我障贸,道長错森,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任篮洁,我火速辦了婚禮涩维,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘袁波。我一直安慰自己瓦阐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布篷牌。 她就那樣靜靜地躺著睡蟋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枷颊。 梳的紋絲不亂的頭發(fā)上戳杀,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機(jī)與錄音夭苗,去河邊找鬼信卡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛题造,可吹牛的內(nèi)容都是我干的傍菇。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼晌梨,長吁一口氣:“原來是場噩夢啊……” “哼桥嗤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仔蝌,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤泛领,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后敛惊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渊鞋,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年瞧挤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锡宋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡特恬,死狀恐怖执俩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情癌刽,我是刑警寧澤役首,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布尝丐,位于F島的核電站,受9級特大地震影響衡奥,放射性物質(zhì)發(fā)生泄漏爹袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一矮固、第九天 我趴在偏房一處隱蔽的房頂上張望失息。 院中可真熱鬧,春花似錦档址、人聲如沸盹兢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛤迎。三九已至,卻和暖如春含友,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背校辩。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工窘问, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宜咒。 一個(gè)月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓惠赫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親故黑。 傳聞我的和親對象是個(gè)殘疾皇子儿咱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348