一、原理簡述
1.1 LR定義
邏輯回歸(Logistic Regression)削葱,簡稱LR,是目前較流行使用廣泛的一種學習算法淳梦,用于解決預測的變量y是離散值的二分類問題析砸。例如:判斷一封電子郵件是否是垃圾( 0 or 1)。Y=0表示為非垃圾郵件爆袍,Y=1為是垃圾郵件首繁,這里的響應變量是一個兩點(0-1)分布變量,但不能用h函數(shù)連續(xù)的值來預測因變量Y螃宙,只能取0或1解決二分類問題。
邏輯回歸的模型本質(zhì)上是一個線性回歸模型所坯,假設因變量 ?? 服從伯努利分布谆扎,通過Sigmoid函數(shù)引入了非線性因素處理0/1分類問題。
1.2 Sigmoid函數(shù)
邏輯回歸模型的假設是: h??(??) = ??(??????) 其中: ?? 代表特征向量 ?? 代表邏輯函數(shù)(logistic function)是一個常用的邏輯函數(shù)為 S 形函數(shù)(Sigmoid function) 芹助,該模型的輸出變量范圍始終在 0 和 1 之間 堂湖。公式為:
該函數(shù)的圖像為:
邏輯回歸模型的假設:
h?? (??) = ?? (?? = 1|??; ??)
h??(??)的作用是闲先,對于給定的輸入變量,根據(jù)選擇的參數(shù)計算輸出變量=1 的可能性无蜂,例如伺糠,假設給定的??,通過已經(jīng)確定的參數(shù)計算得出h?? (??) = 0.7斥季,則表示有 70%的幾率??為正向類训桶,相應地??為負向類的幾率為 1-0.7=0.3 。
1.3 決策邊界
決策邊界(decision boundary) 可以理解為將樣本劃分為不同類別的一條邊界酣倾。
在邏輯回歸中舵揭,我們預測:
當h??(??) >= 0.5時,預測 ?? = 1躁锡。
當h??(??) < 0.5時午绳,預測 ?? = 0。
根據(jù)上面繪制出的 S 形函數(shù)圖像映之,我們知道當
??=0 時 ??(??)=0.5
??>0 時 ??(??)>0.5
??<0 時 ??(??)<0.5
又 ?? = ?????? 拦焚,即:
?????? >= 0 時,預測 ?? = 1
?????? < 0 時杠输,預測 ?? = 0
sigmoid函數(shù)將回歸函數(shù)得到的值求得一個介于0和1之間的概率赎败,當h??(??)>0.5時,預測值為1抬伺,ph??(??)<0.5時螟够,預測值為0。那么h??(??)=0.5就是一個臨界值峡钓,此時e的系數(shù)就是0妓笙,決策邊界的公式為:
這里引用Andrew Ng 課程上的兩張圖來解釋這個問題:
1.3.1 線性決策邊界
參數(shù)?? 是向量[-3 1 1]。 則當?3 + ??1 + ??2 ≥ 0能岩,即??1 + ??2 ≥ 3時寞宫,模型將預測 ?? = 1。 我們可以繪制直線??1 + ??2 = 3拉鹃,這條線便是我們模型的分界線辈赋,將預測為 1 的區(qū)域和預 測為 0 的區(qū)域分隔開。
1.3.1 非線性決策邊界
因為需要用曲線才能分隔 ?? = 0 的區(qū)域和 ?? = 1 的區(qū)域膏燕,我們需要二次方特征: h (??)=??(?? +?? ?? +?? ?? +?? ??2 +?? ??2)是[-1 0 0 1 1]钥屈,則我們得到的判定邊界恰好是圓點在原點且半徑為 1 的圓形。
1.4 代價函數(shù)
對于線性回歸模型坝辫,我們定義的代價函數(shù)是所有模型誤差的平方和篷就。 公式為:
但對于邏輯回歸來說,邏輯回歸是一個非凸函數(shù)(non-convexfunction)近忙,意味著會出現(xiàn)很多局部最小值竭业,這也將會影響梯度下降算法尋找全局最優(yōu)解智润。
邏輯回歸的代價函數(shù)為:
!
h??(??)與 ????????(h??(??),??)之間的關系如下圖所示:
當實際的 ?? = 1 且h??(??)也為 1 時誤差為 0, 當 ?? = 1 但h??(??)不為 1 時誤差隨著h??(??)變小而變大;當實際的 ?? = 0 且h??(??)也為 0 時 代價為 0未辆,當?? = 0 但h??(??)不為 0 時誤差隨著 h??(??)的變大而變大窟绷。
1.5 梯度下降法
最小化代價函數(shù)的方法,是使用梯度下降法(gradient descent)咐柜。 梯度下降中的梯度指的是代價函數(shù)對各個參數(shù)的偏導數(shù)兼蜈,偏導數(shù)的方向決定了在學習過程中參數(shù)下降的方向,學習率(通常用α表示)決定了每步變化的步長炕桨,有了導數(shù)和學習率就可以使用梯度下降算更新參數(shù), 即 :
1.6 多類別分類:一對多
邏輯回歸本身只能解決二分類問題饭尝,但可以通過一些方法使得二分類轉(zhuǎn)換成多分類問題。常見的方式有OvR和OvO兩種献宫。
舉個例子钥平,如果一個病人因為鼻塞來去醫(yī)院看病,他可能并沒有生病姊途,用 ?? = 1 這個類別來代表涉瘾;或者患了感冒,用 ?? = 2 來代表捷兰;或者得了流感用?? = 3來代表立叛。例子為一個多分類問題。前面我們已經(jīng)知道使用邏輯回歸進行二元分類贡茅,對于直線或許你也知道秘蛇,可以將數(shù)據(jù)集一分為二為正類和負類。用一對多的分類思想顶考,我們可以將其用在多類分類問題上赁还,這種方法為"一對余"方法 ,也稱OvR(One vs Rest)驹沿。
上圖為多分類轉(zhuǎn)換成二分類過程艘策,圖中原有紅、藍渊季、紫朋蔫、綠四個類別。以左下角為例却汉,假設紅色類標記為正向類(?? = 1)驯妄,而灰色類(除紅色外的其他類標記為負向類(?? = 0)。接著合砂,類似地選擇另一個類標記為正向類(?? = 2)青扔,再將其它類都標記為負向類,最后我們得到一系列的模型簡記為: h?? (??)(??) = ??(?? = ??|??; ??)其中:?? = (1,2,3. . . . ??) 。
簡單來說赎懦,OvR的思路是將所有類別分為兩個類,當前類別是一類幻工,其他類別合并視為一個類励两。有K個類別的數(shù)據(jù)樣本就會被分為K個由兩個類組成的新樣本集合,這樣就將多分類問題轉(zhuǎn)化為二分類問題囊颅,然后對每個數(shù)據(jù)樣本進行模型訓練当悔,得到模型使用樣本進行驗證,選擇分類得分最高的作為最終的樣本類別踢代。
二盲憎、代碼實現(xiàn)
2.1 手寫批量梯度下降
import numpy as np
from sklearn.metrics import mean_squared_error
import sklearn.datasets as dataset
from sklearn.model_selection import train_test_split
class Logistic_Regression:
def __init__(self):
'''
初始化Logistic Regression模型
'''
self.coef_ = None
self.interept_ = None
self._theta = None
def _sigmoid(self, t):
'''
sigmoid函數(shù)
:param t:
:return:
'''
return 1 / (1 + np.exp(-t))
def fit(self, X_train, y_train, eta=0.01, n_iters=1e4, epsilon=0.0001):
'''
梯度下降
:param X_train:
:param y_train:
:param eta:
:param n_iters:
:return:
'''
assert X_train.shape[0] == y_train.shape[0], 'the size of X_train must equals the size of y_train'
def J(theta, X_b, y):
'''
計算代價
:param theta:
:param X_b:
:param y:
:return:
'''
y_hat = self._sigmoid(X_b.dot(theta))
try:
return - np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) / len(y)
except:
return float('inf')
def dJ(theta, X_b, y):
'''
計算梯度
:param theta:
:param X_b:
:param y:
:return:
'''
return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(X_b)
def gradient_descent(X_b, y, theta_init, eta=eta, n_iters=n_iters, epsilon=epsilon):
'''
梯度下降
:param X_b:
:param y:
:param theta_init:
:param eta:
:param n_iters:
:param epsilon:
:return:
'''
theta = theta_init
cur_iters = 0
while cur_iters < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - gradient * eta
if abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon:
break
cur_iters = cur_iters + 1
return theta
X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
theta_init = np.zeros(X_b.shape[1])
self._theta = gradient_descent(X_b, y_train, theta_init, eta, n_iters, epsilon)
self.interept_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
def predict_probability(self, X_test):
'''
預測概率函數(shù)
:param X_test:
:return:
'''
assert self.coef_ is not None, 'coef can not be None'
assert X_test.shape[1] == len(self.coef_), 'the size of X_test must equals the size of coef'
X_b = np.hstack([np.ones((len(X_test), 1)), X_test])
return self._sigmoid(X_b.dot(self._theta))
def predict(self, X_test):
'''
預測函數(shù)
:param X_test:
:return:
'''
assert self.coef_ is not None, 'coef can not be None'
assert X_test.shape[1] == len(self.coef_), 'the size of X_test must equals the size of coef'
prob = self.predict_probability(X_test)
return np.array(prob >= 0.5, dtype='int')
def mse(self, X_test, y_test):
'''
測試預測準確度
:param X_test:
:param y_test:
:return:
'''
y_predict = self.predict(X_test)
return mean_squared_error(y_predict, y_test)
data = dataset.load_iris()
X = data.data
y = data.target
X = X[y < 2, :2]
y = y[y<2]
X_train, X_test, y_train, y_test = train_test_split(X, y)
logistics = Logistic_Regression()
logistics.fit(X_train, y_train)
mse = logistics.mse(X_test, y_test)
print(mse)
print("the coef of 2 features:"f )
定義一個Logistic_Regression類,通過coef_和interept_記錄特征的系數(shù)和回歸曲線的截距胳挎。fit()函數(shù)封裝了梯度下降相關的所有函數(shù)饼疙,包括代價函數(shù)J、求梯度的函數(shù)dJ以及梯度下降函數(shù)gradient_descent()慕爬,gradient_descent()函數(shù)的執(zhí)行過程和總結線性回歸時的批量梯度下降基本一樣窑眯,不過是代價函數(shù)和求梯度的方式有所變化而已。之后可以調(diào)用predict()方法進行測試預測并使用mse函數(shù)求預測值與實際值之間的均方誤差檢驗模型預測效果医窿。
聲明:此文章為本人學習筆記磅甩,課程來源于:
1、吳恩達機器學習課程
2姥卢、慕課網(wǎng):python3入門機器學習經(jīng)典算法與應用卷要。