5. Logistic回歸
阿新 • • 發佈:2018-01-27
時間 條件 決策 1+n 們的 marker from 等等 pandas 一、介紹
Logistic回歸是廣泛應用的機器學習算法,雖然名字裏帶“回歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別)。
面對一個回歸或者分類問題,建立代價函數(損失函數),使用最優化算法(梯度上升法、改進的隨機梯度上升法),找到最佳擬合參數,將數據擬合到一個logit函數(或者叫做logistic函數)中,得到定性變量y,比如y=0或1,從而預測事件發生的概率。
二、線性回歸
從線性回歸說,多維空間中存在的樣本點,用特征的線性組合去擬合空間中點的分布和軌跡。如下圖所示:
線性回歸能對連續值結果進行預測,現實生活中存在另一種分類-----是與否的二分類問題。比如醫生需要判斷病人是否生病,銀行要判斷一個人的信用程度是否達到可以給他發信用卡的程度,郵件收件箱要自動對郵件分類為正常郵件和垃圾郵件等等。
當然,既然能夠用線性回歸預測出連續值結果,那根據結果設定一個閾值是不是就可以解決這個問題了呢?事實是,對於很標準的情況,確實可以。下圖中X為數據點腫瘤的大小,Y為觀測結果是否是惡性腫瘤。如hθ(x)所示,構建線性回歸模型,然後設定一個閾值0.5,預測hθ(x)≥0.5的這些點為惡性腫瘤,而hθ(x)<0.5為良性腫瘤。
上圖中突然有一個wrong的數據點,再根據設定的0.5,得出的分類就是錯誤的(良性腫瘤錯誤認為是惡性腫瘤),而現實生活中分類問題的數據,會比上述舉例更復雜,借助線性回歸+閾值的方式,很難完成一個魯棒性很好的分類器。
相比線性回歸,邏輯回歸:
1. 線性回歸的結果是一個連續值,值的範圍是無法限定的,假設回歸的結果都是無法限定的值,那做出一個判定就很難了。能將結果做一個映射,輸出(0,1) 的一個概率值,這個問題就很清楚了。有這樣一個簡單的函數,可以做到這樣的映射---sigmoid函數。
說明:從sigmoid函數圖像可以看出,函數 hθ(x) = g(z): 在z=0的時候.函數值 1/2,隨著 z 逐漸變小函數值趨於0,z 逐漸變大函數值逐漸趨於1,而這正是一個概率的範圍。
我們定義線性回歸的預測函數為hθ(x) = θTX,那麽邏輯回歸的輸出hθ(x) = g( θTX ),其中 g( z ) 函數就是上述sigmoid函數.
hθ(x) = g( θTX ) ≥ 0.5, 則 θTX ≥ 0, 意味著類別為 1;
hθ(x) = g( θTX ) < 0.5, 則 θTX < 0, 意味著類別為 0;
所以可以認為 θTX =0 是一個決策邊界,當它 >0 或 <0 時,邏輯回歸模型預測出不同的分類結果。
2. 邏輯回歸可以做出直線、圓或者是曲線這樣的判定邊界,比較好地將兩類樣本分開。
說明:假設 hθ(x)=g(θ0+θ1X1+θ2X2),其中θ0 ,θ1 ,θ2分別取-3, 1, 1。則當?3+X1+X2 ≥ 0時, y = 1即類別為1; 則X1+X2 = 3是一個判定邊界,圖形表示如下,剛好把圖上的兩類點區分開來:
假設hθ(x) 比較復雜,hθ(x) = g(θ0+θ1X1+θ2X2+ θ3 X12+ θ4X22) ,其中θ0 ,θ1 ,θ2,θ3 ,θ4 分別取-1, 0, 0,1,1,則當 -1 + x12+x22 ≥ 0 時,y = 1即類別為1; 則x12+x22 = 1是一個判定邊界,圖形表示如下:
所以,只要我們的hθ(x)設計足夠合理,準確的說是g(θTx)中θTx足夠復雜,能在不同的情形下,擬合出不限於線性的判定邊界。
三、求解θ
假設我們有n個獨立的訓練樣本{(x1, y1) ,(x2, y2),…, (xn, yn)},類別y = {0, 1}。那每一個觀察到的樣本(xi, yi)出現的概率是:
y的取值為0 或 1,所以,上式等價於:
那整個樣本集,n個獨立的樣本出現的似然函數為(因為每個樣本都是獨立的,所以n個樣本出現的概率就是它們各自出現的概率相乘):
連乘不好處理,取自然對數,轉成相加:
經過化簡得到:
該似然函數在這裏表示的是:參數取值為θ時,取得當前這個樣本集的可能性。使參數為θ的似然函數L(θ)極大化,然後極大值對應的θ就是我們的估計。
假如需要求如下函數的最大值:
函數的導數為:
所以 x=1.5即取得函數的最大值1.25。
同樣的,我們對剛剛的對數似然函數logL(θ)即l(θ)求導:
然後我們令該導數為0,你會很失望的發現,它無法解析求解。
終於可以說梯度上升了……利用叠代公式:
參數α叫學習率,就是每一步走多遠,這個參數蠻關鍵的。如果設置的太多,那麽很容易就在最優值附近徘徊,因為步伐太大了。它帶來的好處是能很快的從遠離最優值的地方回到最優值附近,只是在最優值附近的時候,它有心無力了。但如果設置的太小,那收斂速度就太慢了,向蝸牛一樣,雖然會落在最優的點,但是速度太慢。所以學習率可以改進,開始叠代時,學習率大,慢慢的接近最優值的時候,學習率變小就可以了,即隨機梯度下降算法。
所以,最終我們計算過程(訓練過程)如下:
1. 根據權重和訓練樣本計算估計值
2.計算誤差
3. 叠代更新
叠代停止條件:到達限定叠代次數 或者 誤差 <= 設定誤差的最小值。 說明:以上過程中,n 和 m等價,w 和 θ等價。 四、 代碼
叠代停止條件:到達限定叠代次數 或者 誤差 <= 設定誤差的最小值。 說明:以上過程中,n 和 m等價,w 和 θ等價。 四、 代碼
1 import numpy as np 2 import re 3 from pandas import DataFrame 4 import time as time 5 import matplotlib.pyplot as plt 6 import math 7 8 def get_data(filename): #讀取數據 9 f = open(filename) 10 data = DataFrame(columns=[‘x0‘,‘x1‘,‘x2‘,‘label‘]) #構造DataFrame存放數據,列名為x與y 11 line = f.readline() 12 line = line.strip() 13 p = re.compile(r‘\s+‘) #由於數據由若幹個空格分隔,構造正則表達式分隔 14 while line: 15 line = line.strip() 16 linedata = p.split(line) 17 data.set_value(len(data),[‘x0‘,‘x1‘,‘x2‘,‘label‘],[1,float(linedata[0]),float(linedata[1]),int(linedata[2])]) #數據存入DataFrame 18 line = f.readline() 19 return np.array(data.loc[:,[‘x0‘,‘x1‘,‘x2‘]]),np.array(data[‘label‘]) 20 def sigmoid(x): 21 return 1.0/(1+np.exp(-x)) 22 def stocGradAscent(dataMat,labelMat,alpha = 0.01): #隨機梯度上升 23 start_time = time.time() #記錄程序開始時間 24 m,n = dataMat.shape 25 weights = np.ones((n,1)) #分配權值為1 26 for i in range(m): 27 h = sigmoid(np.dot(dataMat[i],weights).astype(‘int64‘)) #註意:這裏兩個二維數組做內積後得到的dtype是object,需要轉換成int64 28 error = labelMat[i]-h #誤差 29 weights = weights + alpha*dataMat[i].reshape((3,1))*error #更新權重 30 duration = time.time()-start_time 31 print(‘time:‘,duration) 32 return weights 33 def gradAscent(dataMat,labelMat,alpha = 0.01,maxstep = 1000): #批量梯度上升 34 start_time = time.time() 35 m,n = dataMat.shape 36 weights = np.ones((n,1)) 37 for i in range(maxstep): 38 h = sigmoid(np.dot(dataMat,weights).astype(‘int64‘)) #這裏直接進行矩陣運算 39 labelMat = labelMat.reshape((100,1)) #label本為一維,轉成2維 40 error = labelMat-h #批量計算誤差 41 weights = weights + alpha*np.dot(dataMat.T,error) #更新權重 42 duration = time.time()-start_time 43 print(‘time:‘,duration) 44 return weights 45 def betterStoGradAscent(dataMat,labelMat,alpha = 0.01,maxstep = 150): 46 start_time = time.time() 47 m,n = dataMat.shape 48 weights = np.ones((n,1)) 49 for j in range(maxstep): 50 for i in range(m): 51 alpha = 4/(1+i+j) + 0.01 #設置更新率隨叠代而減小 52 h = sigmoid(np.dot(dataMat[i],weights).astype(‘int64‘)) 53 error = labelMat[i]-h 54 weights = weights + alpha*dataMat[i].reshape((3,1))*error 55 duration = time.time()-start_time 56 print(‘time:‘,duration) 57 return weights 58 def show(dataMat, labelMat, weights): 59 #dataMat = np.mat(dataMat) 60 #labelMat = np.mat(labelMat) 61 m,n = dataMat.shape 62 min_x = min(dataMat[:, 1]) 63 max_x = max(dataMat[:, 1]) 64 xcoord1 = []; ycoord1 = [] 65 xcoord2 = []; ycoord2 = [] 66 for i in range(m): 67 if int(labelMat[i]) == 0: 68 xcoord1.append(dataMat[i, 1]); ycoord1.append(dataMat[i, 2]) 69 elif int(labelMat[i]) == 1: 70 xcoord2.append(dataMat[i, 1]); ycoord2.append(dataMat[i, 2]) 71 fig = plt.figure() 72 ax = fig.add_subplot(111) 73 ax.scatter(xcoord1, ycoord1, s=30, c="red", marker="s") 74 ax.scatter(xcoord2, ycoord2, s=30, c="green") 75 x = np.arange(min_x, max_x, 0.1) 76 y = (-float(weights[0]) - float(weights[1])*x) / float(weights[2]) 77 ax.plot(x, y) 78 plt.xlabel("x1"); plt.ylabel("x2") 79 plt.show() 80 81 if __name__==‘__main__‘: 82 dataMat,labelMat = get_data(‘data1.txt‘) 83 weights = gradAscent(dataMat,labelMat) 84 show(dataMat,labelMat,weights)
參考:
http://blog.csdn.net/han_xiaoyang/article/details/49123419
https://www.cnblogs.com/chenyang920/p/7426187.html
http://blog.csdn.net/u011197534/article/details/53492915?utm_source=itdadao&utm_medium=referral
http://blog.csdn.net/zouxy09/article/details/8537620
5. Logistic回歸