邏輯回歸原理,推導,及sklearn中的使用
1 從線性回歸過渡到邏輯回歸
對於線性回歸而言,標簽是連續值,線性回歸的任務就是構造一個預測函數來映射輸入的特征矩陣 x 和標簽值 y 的關系,要構造出這個預測函數的核心就是找到參數矩陣 θ^T^,通過預測函數,可以通過輸入的特征矩陣 x ,來得到連續型的預測值。
線性回歸的標簽是連續值,那如果標簽是離散值的呢?具體點就是那種只有 0,1 兩種值的呢?這個時候如果有一個函數,可以使得我們輸入了一個連續值(線性回歸預測出來的結果),把這個值歸一化到 (0, 1) 之間,那么就可以從概率的角度來看,如果這個值大於 0.5,就把其歸類到 1,如果這個值小於 0.5,就把其歸類到 0。此時 Sigmoid 函數就出現了。
Sigmoid 函數:
對於 Sigmoid 函數,在 z > 0 時,0.5 < y < 1,z -> inf ,y -> 1。
線性回歸預測函數 \(z=θ^Tx\) 預測得到的連續值代入Sigmoid函數,便得到了邏輯回歸模型的預測函數 \(y(x)=\frac{1}{1 + e^-z}\)
關於決策邊界的一些解惑:
- 邏輯回歸要做的事情就是找出決策邊界,來划分出兩種不同的分類。對於二維的特征矩陣 x,決策邊界就是一條曲線,對於三維的特征矩陣 x,決策邊界就是一個平面,對於 n 維的特征矩陣 x,決策邊界就是 n-1 維的超平面,決策邊界的構造,是對於特征向量 x~i~ 來說的。
- 決策邊界就是 令 \(y(x)\) = 0,得到的超平面
- 令 $ y(x) > 0$ ,得到的就是 標簽為 1 的樣本,即在決策邊界某一邊的樣本,$ y(x) < 0$ 就是標簽為 0 的樣本,通過決策邊界划分。
建模過程:找出最佳的 θ vector,來使得數據和模型的擬合程度最高,用這個θ vector來構建預測函數y(x),然后將特征矩陣輸入到預測函數來輸出預測結果y。
2 邏輯回歸的損失函數
2.1 邏輯回歸損失函數的推導
要得到參數向量 \(θ^T=[ θ_0,θ_1,θ_2,θ_3...θ_n]\),來最好的擬合出一個模型,就要找出這個模型的損失函數,最小化這個損失函數,來得到對應的 \(θ^T\),那么應該如何得到這個損失函數呢?
首先要理解的一個地方是,經過 Sigmoid 函數進行歸一化的數值是介於 0 到 1 之間的,那么這個值就可以看成是一個概率值,這個概率值的含義是,對於給定的一個樣本 \(x_i\) 和 參數向量 \(θ^T\),該 \(x_i\) 能被預測為 標簽1 的概率,我們把這個概率用 \(y_θ(x_i)\)來表示如下:
樣本 i 由特征向量 \(x_i\) 和 參數向量 θ 組成的預測函數中,樣本被預測為 標簽1 的概率:
樣本 i 由特征向量 \(x_i\) 和 參數向量 θ 組成的預測函數中,樣本被預測為 標簽0 的概率(由於服從0-1分布):
那么把這兩個概率整合得到聯合概率公式,可以得如下形式:
對於一個樣本 i ,當 \(y_i = 0\) 時,\(P(\hat{y}|x_i,θ) = P_0\),此時,我們希望 \(P_0\) 越接近於 1 越好,因為這樣取到 標簽 0 的概率越大。當 \(y_i = 1\) 時,\(P(\hat{y}|x_i,θ) = P_1\),此時,我們希望 \(P_1\) 越接近於 1 越好,因為這樣取到 標簽 1 的概率越大。所以不管怎樣,我們都希望\(P(\hat{y}|x_i,θ)\) 的 取值越大越好,越接近於 1 越好,這樣得到的結果更接近於預期值,即損失更小。所以我們要獲取它的最大值,現在的問題,就由將模型擬合中的“最小化損失”問題,轉換成了對函數求解極值的問題。
那么對數據集中的m個樣本,得到的聯合概率公式:
對聯合概率公式 \(J(θ)\) 兩邊同時取對數,在根據對數運算的公式:
因為此處時求解聯合概率函數的最大值,要轉化為求其最小值,只須求 \(-logJ(\theta)\) 即可,如此,便得到了邏輯回歸的損失函數\(J(\theta)\):
這個推導過程實際上就是"極大似然估計 MLE"的過程。
概率與似然:
- 對於聯合概率函數 \(P(\hat{y}|x_i,θ)\) 而言。
- 概率探究的是自變量與因變量之間的關系,即 \(\theta\) 已知,在不同的特征向量 \(x_i\) 下,得到 \(\hat{y}\) 的可能性。
- 似然**探究的是參數向量與因變量之間的關系,即 \(x_i\) 已知,在不同的參數向量 \(\theta\) 下,得到 \(\hat{y}\) 的可能性。
- 對於邏輯回歸的建模過程,\(\theta\) 是未知的,\(x_i\) 是已知的,所以這里求解的聯合概率函數(似然函數)的結果是 "似然",而因為要最大化似然函數,這個過程稱為 "極大似然"。
求最大似然函數估計的一般步驟:
- 寫出似然函數
- 對似然函數取對數,得到對數似然函數
- 如果對數似然函數可導,就對似然函數求導,解方程組,得到駐點
- 分析駐點為極大值的點
對於邏輯回歸的最大似然函數,要求解對數似然函數可導=0,是一個NP難問題,所以步驟3,4不可行,又因為對數似然函數是一個凸函數,只會存在一個最小值,對於梯度下降法沒有收斂到局部最小值煩惱,所以使用梯度下降法
2.2 梯度下降法
邏輯回歸的建模過程,就是要求解參數向量 \(\theta\) ,使得模型最好的擬合數據。而求解 \(\theta\) 的值是通過最小化損失函數得到的,這個過程使用梯度下降法。
梯度下降法,是一個基於搜索的最優化算法,用來最優化一個損失函數。
姑且來拆解這個方法中的詞:
- 梯度:梯度就是函數值增加得最快的方向,梯度的反方向就是函數值減小得最快的方向
- 下降:沿着梯度下降最快的方向一直走,直到到達函數的最小值,或附近。
梯度下降法的求解過程:
- 在損失函數 \(J(\theta)\) 上隨機選擇一個點,初始化 \(\theta\) 向量的取值,給定一個步長 \(\eta\)
- 求當前位置的梯度 \(gard\) (對自變量求偏導),用參數向量 \(\theta\) 減去 \(gard * \eta\)
- 重復步驟 2 ,直到 \(\theta - gard * \eta\) 的值小於某一個閾值,或者達到最大的迭代次數 max_iter
- 此時對應的參數向量就是損失函數取得最小值的參數向量
根據上面求解梯度下降法的過程,可以得知一個重要的參數 max_iter ,控制着迭代的次數,在 sklearn 里面的 Logistic Regression 是沒有步長這個參數的,這個迭代的過程僅由參數 max_iter 來控制,max_iter 過小,算法可能沒收斂到最小值,max_iter 過大,算法收斂緩慢。
有一個疑問是:max_iter 過大,不會跳過了最小值點嗎?
其實迭代次數多了是沒問題的,因為迭代次數多了后,在到達極值點時,函數對自變量的導數已近乎為0,即使過了極值點,導數就變為正數了,此時,參數向量的值減去步長與梯度的乘積反倒變小了。所以即使步數多了,結果也基本上就在極值點處左右徘徊,幾乎等於極值點。
2.3 正則化
雖然邏輯回歸和線性回歸是天生欠擬合的模型,但我們還是需要控制過擬合來調整模型,對邏輯回歸中過擬合的控制,通過正則化來實現。
常用的正則化有 \(L_1\)正則化和\(L_2\)正則化,分別通過在損失函數后 θ 加上參數向量的L1范式和L2范式的倍數來實現。這個增加的范式成為 "正則項" 或 "懲罰項",利用正則項來約束J(θ) 中θ的取值不至於過大,來防止過擬合。
對應於 Lasso Regression 和 Ridge Regression 的 \(L_1\) 與 \(L_2\) 正則化
\(L_1\) 正則化 很容易把某個參數 \(\theta\) 變為 0,因為這種特性,\(L_1\) 正則化 會篩掉一些特征,可能時有用的特征也可能時沒用的特征。而 \(L_2\) 正則化 只會把 \(\theta\) 變為一個很小的值而不會變為 0。一般都使用,\(L_2\) 正則化,當數據量很大的時候就使用 \(L_1\) 正則化,來篩掉一些特征。
3 用邏輯回歸進行多分類
OvO (One vs One):用不同標簽的數據,兩兩類別之間使用邏輯回歸得到一個分類器(這個分類器用來區分這兩種類別中的某一個),把要預測的樣本傳入到這些分類器當中,得到對應的概率,取在所有分類器對比中概率最高的作為分類結果。
OvR (One vs Rest):取出某一類樣本,和剩下的樣本之間構建分類器(這個分類器是用來區分是這個樣本和不是這個樣本的數據),把要預測的樣本傳入到這些分類器當中,得到對應的概率,取在所有分類器對比中概率最高的作為分類結果。
OvO的分類時間更長,但是結果更加精准。
4 sklearn中的 LogisticRegression
- linear_model.LogisticRegression
4.1 max_iter
控制梯度下降的迭代次數
-
邏輯回歸的運行受到最大迭代次數的強烈影響。
-
max_iter 過小,可能沒有收斂到最小值。
-
max_iter 過大,梯度下降迭代次數過多,模型運行時間緩慢。
4.2 penalty & C
選擇正則項,和正則化強度的系數
參數 | 說明 |
---|---|
penalty | 可以輸入"l1"或"l2"來指定使用哪一種正則化方式,不填寫默認"l2"。注意,若選擇"l1"正則化,參數solver僅能夠使用求解方式”liblinear"和"saga“,若使用“l2”正則化,參數solver中所有的求解方式都可以使用。 |
C | C正則化強度的倒數,必須是一個大於0的浮點數,不填寫默認1.0,即默認正則項與損失函數的比值是1:1。C越小,損失函數會越小,模型對損失函數的懲罰越重,正則化的效力越強,參數會逐漸被壓縮得越來越小。 |
4.3 multi_class
multi_class 表示我們要預測的分類是多分類,還是二分類的
默認值是 'ovr',表示當前處理的是二分類,或以"一對多"的形式處理多分類問題。
'multinomial':表示處理多分類問題。
'auto':表示自動選擇
4.4 solver
求解損失函數的方式
默認是 'liblinear' ,坐標下降法
還有'sag' 隨機平均梯度下降法,其實就是Mini Batch gradient descent,小批量的梯度下降,介於梯度下降法和隨機梯度下降法的擇優方法。
還有 'newton-cg','saga'等方法可選
4.5 class_weight
現實當中正負樣本的比例往往很不平衡,比如100個瀏覽此商品的人中,只有一個人購買了此商品,剩下99個人沒有購買,class_weight就是平衡不同標簽數據樣本的比重,通過給少量的標簽增加權重
參數為'balanced' 和 None,默認為None
因為'balanced'參數比較難用,我們要對不平衡的樣本進行采樣處理,由如下方法
# 使用上采樣(增加樣本量少的樣本的數量)的方法平衡樣本
import imblearn
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42) #實例化 X,y = sm.fit_sample(X,y)
n_sample_ = X.shape[0]
pd.Series(y).value_counts()
n_1_sample = pd.Series(y).value_counts()[1] n_0_sample = pd.Series(y).value_counts()[0]
print('樣本個數:{}; 1占{:.2%}; 0占 {:.2%}'.format(n_sample_,n_1_sample/n_sample_,n_0_sample/n_sample_))
5 邏輯回歸的優點與應用
邏輯回歸的優點
1.LR能以概率的形式輸出結果,而非只是0,1判定
2.對線性關系的擬合效果好,LR的可解釋性強,可控度高
3.訓練快,特征工程(featureengineering)之后效果贊
4.因為結果是概率,可以做排序模型
5.添加特征方便
6.在小型數據上 抗噪不錯
出現的應用場景
1.CTR預估/推薦系統的learningtorank/各種分類場景
2.很多搜索引擎廠的廣告CTR預估基線版是LR
3.電商搜索排序/廣告CTR預估基線版是LR
4.新聞app的推薦和排序基線也是LR
6 本人的一些思考
Sigmoid函數:把線性回歸得到的直線或者曲線變成決策邊界
為什么把線性回歸的值帶入Sigmoid函數就可以變成決策邊界?
假設Sigmoid(z) ,z就是線性回歸的表達式,在sigmoid函數中自變量是z,z分為>0和<0。z=0就是指決策邊界,z>0就是二元分類中的某一類,z<0就是二元分類中的另一類。
關於坐標系:
使用梯度下降獲取損失函數的最小值的時候,縱坐標是J(θ),所有橫坐標是[x1, x2, x3···]
進行分類時,即觀看分類結果,觀看決策邊界時,所有的維度都是x1, x2, x3···xn
對於 n 維的數據,決策邊界就是 n-1 維的超平面
決策邊界就是令Sigmoid函數等於0的那個地方,決策邊界的呈現是對於特征向量來呈現的,即如果有兩個特征x1, x2,那么橫坐標和縱坐標分別為x1, x2,然后畫出決策邊界就是,令
Sigmoid(x1)=0
畫出x2的值。
7 常用代碼
# 畫出決策邊界
def plotData(data, label_x, label_y, label_pos, label_neg, axes=None):
# 獲得正負樣本的下標(即哪些是正樣本,哪些是負樣本)
neg = data[:,2] == 0
pos = data[:,2] == 1
if axes == None:
axes = plt.gca()
axes.scatter(data[pos][:,0], data[pos][:,1], marker='+', c='k', s=60, linewidth=2, label=label_pos)
axes.scatter(data[neg][:,0], data[neg][:,1], c='y', s=60, label=label_neg)
axes.set_xlabel(label_x)
axes.set_ylabel(label_y)
axes.legend(frameon= True, fancybox = True)
# 畫出決策邊界 二維
plt.scatter(45, 85, s=60, c='r', marker='v', label='(45, 85)')
plotData(data, 'Exam 1 score', 'Exam 2 score', 'Admitted', 'Not admitted')
x1_min, x1_max = X[:,1].min(), X[:,1].max(),
x2_min, x2_max = X[:,2].min(), X[:,2].max(),
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
h = sigmoid(np.c_[np.ones((xx1.ravel().shape[0],1)), xx1.ravel(), xx2.ravel()].dot(res.x))
h = h.reshape(xx1.shape)
plt.contour(xx1, xx2, h, [0.5], linewidths=1, colors='b')
陸續補充~~