之前的文章學習了線性迴歸,這次來跟大家分享下我對邏輯迴歸的一些理解。
一、什麼是分類問題?
這個其實很好理解,就比如你手裏有一個蘋果和一個橘子,我們的分類問題就是可以描述爲如何寫一個算法讓計算機認出哪個是蘋果,哪個是橘子。
分類問題的輸出是不連續的離散值,比如設定程序輸出 1 表示蘋果,0 表示橘子。但我們之前學習的線性迴歸的輸出是連續的,如預測房價,肯定不能用 0 和 1 來表示房價。
所以記住一點:分類問題輸出離散值,線性迴歸問題輸出連續值。
二、什麼是邏輯迴歸?
今天要學習的這個邏輯迴歸是屬於分類問題,你可能對「邏輯迴歸」有疑惑,既然是分類問題,爲何要說成迴歸問題?幹嗎不叫邏輯分類問題?
我也覺得有點彆扭,可誰讓大師比我們早生出來呢?如果我們早點出生,發明這個算法,或許就命名爲邏輯分類了,哈哈。
既然改變不了,我們就只能接受了,把他當成分類問題記住即可。
三、邏輯迴歸的假設函數
還記得之前線性迴歸的假設函數嗎,就是預測的模型,我們用的是多項式,但在分類問題中我們就要換模型了,爲啥?
很簡單,我們從分類問題和線性迴歸問題的定義可以知道,線性迴歸問題輸出連續值(房價),邏輯迴歸只輸出離散值(0 1),所以模型的輸出不一樣,因此需要選擇一個能輸出離散值的函數 :
其中 表示特徵向量, 表示待學習的參數向量。
但在機器學習分類問題中,模型輸出 0 或者 1 的前一步通常是確定 0 或者 1 的概率,而不是直接根據實例數據就輸出 0 或 1,比如模型預測是蘋果的概率是 90%,那是橘子的概率就是 10%(因爲概率和爲 1),進而模型認爲該水果是蘋果的可能性最大,所以輸出 1 來表示當前識別的水果是蘋果。
根據這個概率特性,我們的邏輯迴歸假設函數取一個常用的邏輯函數 Sigmoid Function:
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
使用這個函數來做爲邏輯迴歸的假設函數,這樣就能根據輸入參數 來輸出 的可能性了,比如輸出 ,就表示有 90% 的概率是蘋果,有 10% 的概率是橘子。
四、邏輯迴歸的分類邊界
在分類問題中存在分類(決策)邊界(Decision Boundary)的概念,因爲我們最終是要將數據用函數分類,體現在座標系中就是函數曲線把數據分爲 2 類,比如一類是蘋果,一類是橘子。
理解分類邊界的目的就是爲了理解邏輯迴歸的假設函數是如何工作的。下面通過一個小例子說明下分類邊界是如何得出的,其實也容易理解。
我們假設:
- 時,預測 ,蘋果
- 時,預測 ,橘子
從 Sigmoid 函數圖像可以看出:
- : 在 之間
- :
- : 在 之間
又因爲 ,要注意這裏 ,所以上面的假設可以替換爲:
- 時,預測 ,蘋果
- 時,分類邊界!
- 時,預測 ,橘子
用個圖來直觀的說明下:
這個圖已經說明的很詳細了,中間的紅線就是分類邊界 ,兩邊分別是大於 0 和小於 0 的情況,在實際應用中,經常把 合併來表示 。
這個例子的分類邊界是直線,其實分類邊界也可以是非線性邊界,比如一個圓:
以上是兩個簡單的分類邊界例子,實際使用中使用更加複雜的多項式可以擬合很複雜的分類邊界。
五、代價函數和梯度下降
與線性迴歸一樣,邏輯迴歸也需要定義代價函數來求出模型的最優參數 ,不過代價函數不能使用模型誤差的平方和,因爲將邏輯迴歸的假設函數帶入平方誤差的代價函數會導致代價函數不是凸函數,進而代價函數會產生許多局部最優值,對梯度下降求最優值會有很大影響。
由於這個缺點,所以我們需要重新定義邏輯迴歸的代價函數:
函數如下:
這個函數直觀上不好理解,可以用曲線看下:
- 時:當 ,$ Cost -> 0$;當 時 無窮大;
- 時:當 ,$ Cost -> 0$;當 時 無窮大;
可以用一句話來理解這個代價函數:當模型的預測與實際值差異越大,代價值越大。
但是我們發現上面的代價函數是分開的,不方便梯度下降計算,能不能整合到一起呢?還真的可以:
當 時後面項爲 0,當 時,前面項爲 0,正好對應之前的分段表達式,再添加上標代入代價函數 中:
有了代價函數,我們就可以利用之前學會的梯度下降法來迭代求代價函數最小值啦!
六、邏輯迴歸實戰
最後我們來用前面學習的邏輯迴歸技術來對 2 類數據進行分類!
6.1 數據準備
要分類的數據可視化如下,一共只有 2 個類別,所以只需要使用直線決策邊界即可:
6.2 假設函數
def sigmoid(z):
return 1 / (1 + np.exp(-z))
6.3 代價函數
這裏仍然使用向量化代碼表示:
# 邏輯迴歸代價函數
def cost_function(theta, X, y):
# 向量化代碼
return np.mean(-y * np.log(sigmoid(X @ theta)) - (1 - y) * np.log(1 - sigmoid(X @ theta)))
6.4 梯度下降
梯度下降的原理在之前的這篇文章有介紹:
# 梯度計算
# return 梯度的一維數組
def gradient(theta, X, y):
return (1 / len(X)) * X.T @ (sigmoid(X @ theta) - y)
6.5 訓練參數
這裏利用已有的優化手段來優化代價函數(損失函數):
import scipy.optimize as opt
# 用 opt.minimize 來訓練邏輯迴歸的參數
# Newton-CG 是牛頓法家族的一種,利用損失函數二階導數矩陣即海森矩陣來迭代優化損失函數
res = opt.minimize(fun = cost_function, x0 = theta, args = (X, y), method = 'Newton-CG', jac = gradient)
6.6 在訓練集上預測
# 計算 y 在訓練集上的預測值
y_predict = predict(X, final_theta)
# 打印分類報告
print(classification_report(y, y_predict))
報告中的 f1-score 分數分別爲 0.86 和 0.91,說明分類結果還是很不錯的:
6.7 輸出分類邊界
我們用繪圖庫來繪製出預測的分類邊界,可以發現分類邊界能夠比較好分開兩個類別的數據:
OK!今天登龍跟大家分享了邏輯迴歸的原理和實戰編程,大家多多實踐,早日學會!文中完整註釋代碼在我的倉庫中:
https://github.com/DLonng/AI-Notes/tree/master/MachineLearning
大家下期見 😃
本文原創首發於 同名微信公號「登龍」,微信搜索關注回覆「1024」你懂的!