邏輯回歸實踐

參考文章1參考文章2參考文章3
Logistic Regression Classifier邏輯回歸主要思想就是用最大似然概率方法構建出方程,為了最大化方程,利用牛頓梯度上升求解方程參數。

優點:計算代價不高,易于理解和實現。
缺點:容易欠擬合,分類精度可能不高。
使用數據類型:數值型和標稱型數據。

0x01. 引入似然函數

邏輯回歸跟最大似然關系很大,那什么是最大似然呢?
最大似然就是:最大可能嘛~就是根據已知的數據來推斷最大可能的參數,比如假設我們已知高中生的身高符合高斯分布,因此我們隨機抽樣100個學生的身高,由于是隨機抽的,因此可以認為這些學生之間是沒有關系的,是獨立的,因此我同時抽到這100個學生的概率就是這100個樣本的聯合概率了:

參數θ相對于樣本集X的似然函數
這個概率反映了,在概率密度函數的參數是θ時,得到X這組樣本的概率。因為這里X是已知的,也就是說我抽取到的這100個人的身高可以測出來,也就是已知的了。而θ是未知了,則上面這個公式只有θ是未知數,所以它是θ的函數。這個函數放映的是在不同的參數θ取值下,取得當前這個樣本集的可能性,因此稱為參數θ相對于樣本集X的似然函數(likehood function)。記為L(θ)

所以,我們就只需要找到一個參數θ,其對應的似然函數L(θ)最大,也就是說抽到這100個男生(的身高)概率最大。這個叫做θ的最大似然估計量,記為:

有時,可以看到L(θ)是連乘的,所以為了便于分析,還可以定義對數似然函數,將其變成連加的:

然后求導并取0,求出參數就是最佳的參數值。


0x02. 遷移之邏輯回歸&最大似然

我們從里面抓3個球,2個黑球,1個白球。這時候,有人就直接得出了黑球67%,白球占比33%。這個時候,其實這個人使用了最大似然概率的思想,通俗來講,當黑球是67%的占比的時候,我們抓3個球,出現2黑1白的概率最大。我們直接用公式來說明。
假設黑球占比為P,白球為1-P。于是我們要求解MAX(PP(1-P)),顯而易見P=67%時是最有可能得到目前的這個結果的(求解方法:對方程求導,使導數為0的P值即為最優解)

對比邏輯回歸是不是就是一個二分類的問題,是不是跟上面的黑白球分類問題很像?

假設我們有n個獨立的訓練樣本{(x1, y1) ,(x2, y2),…, (xn, yn)},y={0, 1}。那每一個觀察到的樣本(xi, yi)出現的概率是:

不管y是0還是1,上面得到的數,都是(x, y)出現的概率。那我們的整個樣本集,也就是n個獨立的樣本出現的似然函數為(因為每個樣本都是獨立的,所以n個樣本出現的概率就是他們各自出現的概率相乘):
這里我們稍微變換下L(θ):取自然對數,然后化簡,得到:
就知道了。注:有xi的時候,表示它是第i個樣本,下面沒有做區分了,相信你的眼睛是雪亮的),得到:

其中第三步到第四步使用了下面替換。
這時候為求最大值,對L(θ)對θ求導,得到:
然后我們令該導數為0,即可求出最優解。但是這個方程是無法解析求解(這里就不證明了)。最后問題變成了,求解參數使方程L最大化,求解參數的方法梯度上升法(原理這里不解釋了,看詳細的代碼的計算方式應該更容易理解些)。根據這個轉換公式
我們代入參數和特征,求P,也就是發生1的概率。
上面這個也就是常提及的sigmoid函數,俗稱激活函數,最后用于分類(若P(y=1|x;Θ )大于0.5,則判定為1)。
這時候,用L(θ)對θ求導,得到:

然后我們令該導數為0,你會很失望的發現,它無法解析求解。不信你就去嘗試一下。所以沒辦法了,只能借助高大上的迭代來搞定了。這里選用了經典的梯度下降算法

0x03. 優化求解 (link)

梯度下降
Gradient descent 又叫 steepest descent,是利用一階的梯度信息找到函數局部最優解的一種方法,也是機器學習里面最簡單最常用的一種優化方法。它的思想很簡單,和我開篇說的那樣,要找最小值,我只需要每一步都往下走(也就是每一步都可以讓代價函數小一點),然后不斷的走,那肯定能走到最小值的地方,例如下圖所示:


但,我同時也需要更快的到達最小值啊,怎么辦呢?我們需要每一步都找下坡最快的地方,也就是每一步我走某個方向,都比走其他方法,要離最小值更近。而這個下坡最快的方向,就是梯度的負方向了。
對logistic Regression來說,梯度下降算法新鮮出爐,如下:

其中,參數α叫學習率,就是每一步走多遠,這個參數蠻關鍵的。如果設置的太多,那么很容易就在最優值附加徘徊,因為你步伐太大了。例如要從廣州到上海,但是你的一步的距離就是廣州到北京那么遠,沒有半步的說法,自己能邁那么大步,是幸運呢?還是不幸呢?事物總有兩面性嘛,它帶來的好處是能很快的從遠離最優值的地方回到最優值附近,只是在最優值附近的時候,它有心無力了。但如果設置的太小,那收斂速度就太慢了,向蝸牛一樣,雖然會落在最優的點,但是這速度如果是猴年馬月,我們也沒這耐心啊。所以有的改進就是在這個學習率這個地方下刀子的。我開始迭代是,學習率大,慢慢的接近最優值的時候,我的學習率變小就可以了。所謂采兩者之精華啊!

梯度下降:

初始化回歸系數為1
重復下面步驟直到收斂{
        計算整個數據集的梯度
        使用alpha x gradient來更新回歸系數
}
返回回歸系數值

隨機梯度下降:

初始化回歸系數為1
重復下面步驟直到收斂{
        對數據集中每個樣本
        計算該樣本的梯度
        使用alpha xgradient來更新回歸系數
 }
返回回歸系數值

改進的隨機梯度下降:

初始化回歸系數為1
重復下面步驟直到收斂{
       對隨機遍歷的數據集中的每個樣本
       隨著迭代的逐漸進行,減小alpha的值
       計算該樣本的梯度
       使用alpha x gradient來更新回歸系數
    }
返回回歸系數值

0x04. 另一種解釋 (link)

其實為某種形式的回歸建立數學模型并不是一件容易的事情,經過先烈的曲折探索,得出了一個神奇的公式,稱為logit公式:

誒?看似簡潔,然而有什么用呢?里面既沒有X也沒有y呀。。。

先等等,還記得深度學習中經常加在神經網絡的頂層來求后驗概率P(y=j|X)的softmax函數嗎?對就是下面這個熟悉的函數:

對于我們的二分類問題來說,有P(y=0|X)+P(y=1|X)=1,那么如果我們令logit公式中的Q=P(y=0|X)呢?然后P(y=0|X)用softmax函數表示呢?是不是突然被下面推導的過程和結果驚呆了!!!:

而xTΔw的值不就是反映感知機模型的輸出嘛!(即xTΔw>0則預測類別為正,xTΔw<0則預測類別為負)

我們再把xTΔw整理的好看一點,變成更正常的形式:w·x+b。然后就可以得到下面的結論!!!:

這就是我們前面苦苦尋找的邏輯回歸模型!看,隨機變量X與隨機變量Y的關系竟然直接納入了一個模型下面!也就是說后驗概率直接用隨機變量X表示了出來!而不是像貝葉斯定理一樣間接表示后驗概率。

有了上面直接表示的后驗概率,于是建立似然函數,通過極大似然估計來確定模型的參數。因此設:

似然函數就表示為

對數似然函數即:

也就是本文的“淺入”環節的損失函數啦,原來是正兒八經的一步步推出來的!剩下的就交給梯度下降法優化出模型參數吧!

from numpy import *
filename='...\\testSet.txt' #文件目錄
def loadDataSet():   #讀取數據(這里只有兩個特征)
    dataMat = []
    labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])   #前面的1,表示方程的常量。比如兩個特征X1,X2,共需要三個參數,W1+W2*X1+W3*X2
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

def sigmoid(inX):  #sigmoid函數
    return 1.0/(1+exp(-inX))

def gradAscent(dataMat, labelMat): #梯度上升求最優參數
    dataMatrix=mat(dataMat) #將讀取的數據轉換為矩陣
    classLabels=mat(labelMat).transpose() #將讀取的數據轉換為矩陣
    m,n = shape(dataMatrix)
    alpha = 0.001  #設置梯度的閥值,該值越大梯度上升幅度越大
    maxCycles = 500 #設置迭代的次數,一般看實際數據進行設定,有些可能200次就夠了
    weights = ones((n,1)) #設置初始的參數,并都賦默認值為1。注意這里權重以矩陣形式表示三個參數。
    for k in range(maxCycles):
        h = sigmoid(dataMatrix*weights)
        error = (classLabels - h)     #求導后差值
        weights = weights + alpha * dataMatrix.transpose()* error #迭代更新權重
    return weights

def stocGradAscent0(dataMat, labelMat):  #隨機梯度上升,當數據量比較大時,每次迭代都選擇全量數據進行計算,計算量會非常大。所以采用每次迭代中一次只選擇其中的一行數據進行更新權重。
    dataMatrix=mat(dataMat)
    classLabels=labelMat
    m,n=shape(dataMatrix)
    alpha=0.01
    maxCycles = 500
    weights=ones((n,1))
    for k in range(maxCycles):
        for i in range(m): #遍歷計算每一行
            h = sigmoid(sum(dataMatrix[i] * weights))
            error = classLabels[i] - h
            weights = weights + alpha * error * dataMatrix[i].transpose()
    return weights

def stocGradAscent1(dataMat, labelMat): #改進版隨機梯度上升,在每次迭代中隨機選擇樣本來更新權重,并且隨迭代次數增加,權重變化越小。
    dataMatrix=mat(dataMat)
    classLabels=labelMat
    m,n=shape(dataMatrix)
    weights=ones((n,1))
    maxCycles=500
    for j in range(maxCycles): #迭代
        dataIndex=[i for i in range(m)]
        for i in range(m): #隨機遍歷每一行
            alpha=4/(1+j+i)+0.0001  #隨迭代次數增加,權重變化越小。
            randIndex=int(random.uniform(0,len(dataIndex)))  #隨機抽樣
            h=sigmoid(sum(dataMatrix[randIndex]*weights))
            error=classLabels[randIndex]-h
            weights=weights+alpha*error*dataMatrix[randIndex].transpose()
            del(dataIndex[randIndex]) #去除已經抽取的樣本
    return weights

def plotBestFit(weights):  #畫出最終分類的圖
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1])
            ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1])
            ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, 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 main():
    dataMat, labelMat = loadDataSet()
    weights=gradAscent(dataMat, labelMat).getA()
    plotBestFit(weights)

if __name__=='__main__':
    main()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容