【機器學習】邏輯回歸(Logistic Regression)


:最近開始學習《人工智能》選修課,老師提綱挈領的介紹了一番,聽完課只了解了個大概,剩下的細節只能自己繼續摸索。

從本質上講:機器學習就是一個模型對外界的刺激(訓練樣本)做出反應,趨利避害(評價標准)。

 

1. 什么是邏輯回歸?


許多人對線性回歸都比較熟悉,但知道邏輯回歸的人可能就要少的多。從大的類別上來說,邏輯回歸是一種有監督的統計學習方法,主要用於對樣本進行分類。

在線性回歸模型中,輸出一般是連續的,例如$$y = f(x) = ax + b$$,對於每一個輸入的x,都有一個對應的y輸出。模型的定義域和值域都可以是[-∞, +∞]。但是對於邏輯回歸,輸入可以是連續的[-∞, +∞],但輸出一般是離散的,即只有有限多個輸出值。例如,其值域可以只有兩個值{0, 1},這兩個值可以表示對樣本的某種分類,高/低、患病/健康、陰性/陽性等,這就是最常見的二分類邏輯回歸。因此,從整體上來說,通過邏輯回歸模型,我們將在整個實數范圍上的x映射到了有限個點上,這樣就實現了對x的分類。因為每次拿過來一個x,經過邏輯回歸分析,就可以將它歸入某一類y中。

 

邏輯回歸與線性回歸的關系

邏輯回歸也被稱為廣義線性回歸模型,它與線性回歸模型的形式基本上相同,都具有 ax+b,其中a和b是待求參數,其區別在於他們的因變量不同,多重線性回歸直接將ax+b作為因變量,即y = ax+b,而logistic回歸則通過函數S將ax+b對應到一個隱狀態p,p = S(ax+b),然后根據p與1-p的大小決定因變量的值。這里的函數S就是Sigmoid函數

$$S(t) = \frac{1}{1 + e^{-t}}$$

將t換成ax+b,可以得到邏輯回歸模型的參數形式:$$p(x; a,b) = \frac{1}{1 + e^{-(ax+b)}}  ……(1)$$

 

圖1:sigmoid函數的圖像

通過函數S的作用,我們可以將輸出的值限制在區間[0, 1]上,p(x)則可以用來表示概率p(y=1|x),即當一個x發生時,y被分到1那一組的概率。可是,等等,我們上面說y只有兩種取值,但是這里卻出現了一個區間[0, 1],這是什么鬼??其實在真實情況下,我們最終得到的y的值是在[0, 1]這個區間上的一個數,然后我們可以選擇一個閾值,通常是0.5,當y>0.5時,就將這個x歸到1這一類,如果y<0.5就將x歸到0這一類。但是閾值是可以調整的,比如說一個比較保守的人,可能將閾值設為0.9,也就是說有超過90%的把握,才相信這個x屬於1這一類。了解一個算法,最好的辦法就是自己從頭實現一次。下面是邏輯回歸的具體實現。

 

邏輯回歸模型的代價函數

邏輯回歸一般使用交叉熵作為代價函數。關於代價函數的具體細節,請參考代價函數,這里只給出交叉熵公式:

$$J(\theta) = -\frac{ 1 }{ m }[\sum_{ i=1 }^{ m } ({y^{(i)} \log h_\theta(x^{(i)}) + (1-y^{(i)}) \log (1-h_\theta(x^{(i)})})]$$

m:訓練樣本的個數;

hθ(x):用參數θ和x預測出來的y值;

y:原訓練樣本中的y值,也就是標准答案

上角標(i):第i個樣本

 

2. 數據准備


下面的數據來自《機器學習實戰》中的示例:

-0.017612	14.053064	0
-1.395634	4.662541	1
-0.752157	6.538620	0
-1.322371	7.152853	0
0.423363	11.054677	0
0.406704	7.067335	1
0.667394	12.741452	0
-2.460150	6.866805	1
0.569411	9.548755	0
-0.026632	10.427743	0

 

上面的數據一共是3列10行,其中前兩列為x1和x2的值,第3列表示y的值;10行表示取了10個樣本點。我們可以將這些數據當做訓練模型參數的訓練樣本。

見到訓練樣本就可以比較直觀的理解算法的輸入,以及我們如何利用這些數據來訓練邏輯回歸分類器,進而用訓練好的模型來預測新的樣本(檢測樣本)。

從邏輯回歸的參數形式,式子(1)我們可以看到邏輯回歸模型中有兩個待定參數a(x的系數)和b(常數項),我們現在給出來的數據有兩個特征x1, x2,因此整個模型就增加了一項:ax1 + cx2 + b。為了形式上的統一,我們使用帶下標的a表示不同的參數(a0表示常數項b並作x0的參數<x0=1>,a1、a2分別表示x1和x2的參數),就可以得到:

$$ a_0x_0 + a_1x_1 + a_2x_2 $$

這樣統一起來后,就可以使用矩陣表示了(比起前面展開的線性表示方式,用矩陣表示模型和參數更加簡便,而且矩陣運算的速度也更快):

$$ \begin{bmatrix} a_0 & a_1 & a_2 \end{bmatrix}  \begin{bmatrix} x_0 \\ x_1 \\ x_2 \end{bmatrix} = a^{ \mathrm{ T } }X$$

 

 將上面的式子帶入到(1)式,我們就可以得到邏輯回歸的另一種表示形式了:

 $$p(x; a) = \frac{1}{1 + e^{-a^{ \mathrm{ T } }X}}  ……(2)$$

 此時,可以很清楚的看到,我們后面的行動都是為了確定一個合適的a(一個參數向量),使得對於一個新來的X(也是一個向量),我們可以盡可能准確的給出一個y值,0或者1.

 

注:數據是二維的,也就是說這組觀察樣本中有兩個自變量,即兩個特征(feature)。

 

3. 訓練分類器


就像上面說的,訓練分類器的過程,就是根據已經知道的數據(訓練樣本)確定一個使得代價函數的值最小的a(參數向量/回歸系數)的過程。邏輯回歸模型屬於有監督的學習方法,上面示例數據中的第3列其實是訓練樣本提供的"標准答案"。也就是說,這些數據是已經分好類的(兩類,0或者1)。在訓練階段,我們要做的就是利用訓練樣本和(2)式中的模型,估計一個比較合適的參數a,使得僅通過前面兩列數據(觀察值/測量值)就可以估計一個值h(a),這個值越接近標准答案y,說明我們的模型預測的越准確。

 

下面是估計回歸系數a的值的過程,還是借鑒了《機器學習實戰》中的代碼,做了少量修改:

其中計算參數梯度,即代價函數對每個參數的偏導數(下面代碼中的第36-38行),的詳細推導過程可以參考這里

 1 '''
 2 Created on Oct 27, 2010
 3 Logistic Regression Working Module
 4 @author: Peter
 5 '''
 6 from numpy import *
 7 import os
 8 
 9 path = 'D:\MechineLearning\MLiA_SourceCode\machinelearninginaction\Ch05'
10 training_sample = 'trainingSample.txt'
11 testing_sample = 'testingSample.txt'
12 
13 # 從文件中讀入訓練樣本的數據,同上面給出的示例數據
14 # 下面第20行代碼中的1.0表示x0 = 1
15 def loadDataSet(p, file_n):
16     dataMat = []; labelMat = []
17     fr = open(os.path.join(p, file_n))
18     for line in fr.readlines():
19         lineArr = line.strip().split()
20         dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])  # 三個特征x0, x1, x2 21         labelMat.append(int(lineArr[2]))  # 標准答案y 22     return dataMat,labelMat
23 
24 def sigmoid(inX):
25     return 1.0/(1+exp(-inX))
26 
27 # 梯度下降法求回歸系數a,由於樣本量少,我將迭代次數改成了1000次
28 def gradAscent(dataMatIn, classLabels):
29     dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
30     labelMat = mat(classLabels).transpose() #convert to NumPy matrix
31     m,n = shape(dataMatrix)
32     alpha = 0.001  # 學習率
33     maxCycles = 1000
34     weights = ones((n,1))
35     for k in range(maxCycles):              # heavy on matrix operations
36         h = sigmoid(dataMatrix*weights)     # 模型預測值, 90 x 1
37         error = h - labelMat                # 真實值與預測值之間的誤差, 90 x 1
38         temp = dataMatrix.transpose()* error # 交叉熵代價函數對所有參數的偏導數, 3 x 1
39         weights = weights - alpha * temp  # 更新權重
40     return weights
41 
42 # 下面是我自己寫的測試函數
43 def test_logistic_regression():
44     dataArr, labelMat = loadDataSet(path, training_sample)  # 讀入訓練樣本中的原始數據
45     A = gradAscent(dataArr, labelMat)  # 回歸系數a的值
46     h = sigmoid(mat(dataArr)*A)  #預測結果h(a)的值
47     print(dataArr, labelMat)
48     print(A)
49     print(h)
50     # plotBestFit(A)
51 
52 test_logistic_regression()

 

上面代碼的輸出如下:

  • 一個元組,包含兩個數組:第一個數組是所有的訓練樣本中的觀察值,也就是X,包括x0, x1, x2;第二個數組是每組觀察值對應的標准答案y。
([[1.0, -0.017612, 14.053064], [1.0, -1.395634, 4.662541], [1.0, -0.752157, 6.53862], [1.0, -1.322371, 7.152853], [1.0, 0.423363, 11.054677], [1.0, 0.406704, 7.067335], [1.0, 0.667394, 12.741452], [1.0, -2.46015, 6.866805], [1.0, 0.569411, 9.548755], [1.0, -0.026632, 10.427743]], [0, 1, 0, 0, 0, 1, 0, 1, 0, 0])  

 

  • 本次預測出來的回歸系數a,包括a0, a1, a2
[[ 1.39174871]
[-0.5227482 ]
[-0.33100373]]  

 

  • 根據回歸系數a和(2)式中的模型預測出來的h(a)。這里預測得到的結果都是區間(0, 1)上的實數。
[[ 0.03730313]
[ 0.64060602]
[ 0.40627881]
[ 0.4293251 ]
[ 0.07665396]
[ 0.23863652]
[ 0.0401329 ]
[ 0.59985228]
[ 0.11238742]
[ 0.11446212]]  

標准答案是{0, 1},如何將預測到的結果與標准答案y進行比較呢?取0.5作為閾值,大於該值的樣本就划分到1這一組,小於等於該值的樣本就划分到0這一組,這樣就可以將數據分為兩類。檢查一下結果可以看到,我們現在分出來的1這一類中包括原來y=1的兩個樣本,另一類包括原來y=0的所有樣本和一個y=1的樣本(分錯了)。鑒於我們選擇取的樣本比較少(只有10個),這樣的效果其實還算非常不錯的!

 

 4. 結果展示


上面已經求出了一組回歸系數,它確定了不同類別數據之間的分割線。可以利用X內部(x1與x2之間的關系)的關系畫出該分割線,從而更直觀的感受到分類的效果。

 

添加下面一段代碼:

 1 # 分類效果展示,參數weights就是回歸系數
 2 def plotBestFit(weights):
 3     import matplotlib.pyplot as plt
 4     dataMat,labelMat=loadDataSet(path, training_sample)
 5     dataArr = array(dataMat)
 6     n = shape(dataArr)[0]
 7     xcord1 = []; ycord1 = []
 8     xcord2 = []; ycord2 = []
 9     for i in range(n):
10         if int(labelMat[i])== 1:
11             xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
12         else:
13             xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
14     fig = plt.figure()
15     ax = fig.add_subplot(111)
16     ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
17     ax.scatter(xcord2, ycord2, s=30, c='green')
18     x = arange(-3.0, 3.0, 0.1)
19     y = (-weights[0]-weights[1]*x)/weights[2]  # x2 = f(x1)
20     ax.plot(x.reshape(1, -1), y.reshape(1, -1))
21     plt.xlabel('X1'); plt.ylabel('X2');
22     plt.show()

將上面的test_logistic_regression()函數中的最后一句注釋去掉,調用plotBestFit函數就可以看到分類的效果了。

這里說明一下上面代碼中的第19行,這里設置了sigmoid函數的取值為1/2,也就是說取閾值為0.5來划分最后預測的結果。這樣可以得到$$e^{-a^{ \mathrm{ T } }X} = 1$$,即$-a^TX=0$,可以推出$x_2 = (-a_0x_0 - a_1x_1)/a_2$,同第19行,也就是說這里的$y$實際上是$x_1$,而$x$是$x_1$。因此下圖表示的是$x_1$與$x_2$之間的關系。

分類效果圖如下:

三個紅色的點是原來$y=1$的樣本,有一個分錯了。這里相當於將所有的數據用二維坐標(x1, x2)表示了出來,而且根據回歸參數畫出的線將這些點一分為二。如果有新的樣本,不知道在哪一類,只用將該點畫在圖上,看它在這條直線的哪一邊就可以分類了。

 

下面是使用90個訓練樣本得到的結果:

可以看出一個非常明顯的規律是,$y=1$的這一類樣本(紅色的點)具有更小的$x_2$值,當$x_2$相近時則具有更大的$x_1$值。

此時計算出來的回歸系數a為:

[[ 5.262118 ]
[ 0.60847797]
[-0.75168429]]

 

5. 預測新樣本


添加一個預測函數,如下:

直接將上面計算出來的回歸系數a拿來使用,測試數據其實也是《機器學習實戰》這本書中的訓練數據,我拆成了兩份,前面90行用來做訓練數據,后面10行用來當測試數據。

1 def predict_test_sample():
2     A = [5.262118, 0.60847797, -0.75168429]  # 上面計算出來的回歸系數a
3     dataArr, labelMat = loadDataSet(path, testing_sample)  
4     h_test = sigmoid(mat(dataArr) * mat(A).transpose())  # 將讀入的數據和A轉化成numpy中的矩陣
5     print(h_test)  # 預測的結果

 

調用上面的函數,可以得到以下結果,即h(a):

[[ 0.99714035]
[ 0.04035907]
[ 0.12535895]
[ 0.99048731]
[ 0.98075409]
[ 0.97708653]
[ 0.09004989]
[ 0.97884487]
[ 0.28594188]
[ 0.00359693]]

 

下面是我們的測試數據(原來的訓練樣本后十行的數據,包括標准答案y):

0.089392	-0.715300	1
1.825662	12.693808	0
0.197445	9.744638	0
0.126117	0.922311	1
-0.679797	1.220530	1
0.677983	2.556666	1
0.761349	10.693862	0
-2.168791	0.143632	1
1.388610	9.341997	0
0.317029	14.739025	0

 

比較我們預測得到的h(a)和標准答案y,如果按照0.5為分界線的話,我們利用前90個樣本訓練出來的分類器對后面10個樣本的類型預測全部正確。

 

 

附件:

github上的代碼更新到python3.6, 2019-1-6

完整代碼:https://github.com/OnlyBelter/MachineLearning_examples/tree/master/de_novo/regression

訓練數據:https://github.com/OnlyBelter/MachineLearning_examples/blob/master/de_novo/data/Logistic_Regression-trainingSample.txt

測試數據:https://github.com/OnlyBelter/MachineLearning_examples/blob/master/de_novo/data/Logistic_Regression-testingSample.txt

 

參考:

http://baike.baidu.com/item/logistic%E5%9B%9E%E5%BD%92

https://en.wikipedia.org/wiki/Sigmoid_function

《機器學習實戰》,哈林頓著,李銳等譯,人民郵電出版社,2013年6月第一版

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM