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

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

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

 

1. 什麼是邏輯迴歸?


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

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

 

邏輯迴歸與線性迴歸的關係

邏輯迴歸也被稱爲廣義線性迴歸模型,它與線性迴歸模型的形式基本上相同,都具備 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)$$app

 

圖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月初版

相關文章
相關標籤/搜索