1. 程式人生 > >資料科學和人工智慧技術筆記 十二、邏輯迴歸

資料科學和人工智慧技術筆記 十二、邏輯迴歸

十二、邏輯迴歸

作者:Chris Albon

譯者:飛龍

協議:CC BY-NC-SA 4.0

C 超引數快速調優

有時,學習演算法的特徵使我們能夠比蠻力或隨機模型搜尋方法更快地搜尋最佳超引數。

scikit-learn 的LogisticRegressionCV方法包含一個引數C。 如果提供了一個列表,C是可供選擇的候選超引數值。 如果提供了一個整數,C的這麼多個候選值,將從 0.0001 和 10000 之間的對數標度(C的合理值範圍)中提取。

# 載入庫
from sklearn import linear_model, datasets

# 載入資料
iris = datasets.load_iris() X = iris.data y = iris.target # 建立邏輯迴歸的交叉驗證 clf = linear_model.LogisticRegressionCV(Cs=100) # 訓練模型 clf.fit(X, y) ''' LogisticRegressionCV(Cs=100, class_weight=None, cv=None, dual=False, fit_intercept=True, intercept_scaling=1.0, max_iter=100, multi_class='ovr', n_jobs=1, penalty='l2', random_state=None, refit=True, scoring=None, solver='lbfgs', tol=0.0001, verbose=0) '''

在邏輯迴歸中處理不平衡類別

像 scikit-learn 中的許多其他學習演算法一樣,LogisticRegression帶有處理不平衡類的內建方法。 如果我們有高度不平衡的類,並且在預處理期間沒有解決它,我們可以選擇使用class_weight引數來對類加權,確保我們擁有每個類的平衡組合。 具體來說,balanced引數會自動對類加權,與其頻率成反比:

w j =

n k n j w_j = \frac{n}{kn_{j}}

其中 w j w_j 是類 j j 的權重, n n 是觀察數, n j n_j 是類 j j 中的觀察數, k k 是類的總數。

# 載入庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import numpy as np

# 載入資料
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 通過移除前 40 個觀測,使類高度不均衡
X = X[40:,:]
y = y[40:]

# 建立目標向量,如果表示類別是否為 0
y = np.where((y == 0), 0, 1)

# 標準化特徵
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 建立決策樹分類器物件
clf = LogisticRegression(random_state=0, class_weight='balanced')

# 訓練模型
model = clf.fit(X_std, y)

邏輯迴歸

儘管其名稱中存在“迴歸”,但邏輯迴歸實際上是廣泛使用的二分類器(即,目標向量只有兩個值)。 在邏輯迴歸中,線性模型(例如 β 0 + β 1 x \beta_{0} + \beta_ {1} x )包含在 logit(也稱為 sigmoid)函式中,KaTeX parse error: Expected '}', got 'EOF' at end of input: …{1}{1 + e^{-z}},滿足:

P ( y i = 1 X ) = 1 1 + e ( β 0 + β 1 x ) P(y_i=1 \mid X)={\frac{1}{1+e^{-(\beta_{0}+\beta_{1}x)}}}

其中 P ( y i = 1 X ) P(y_i=1 \mid X) 是第 i i 個觀測的目標值 y i y_i 為 1 的概率, X X 是訓練資料, β 0 \beta_0 β 1 \beta_1 是要學習的引數, e e 是自然常數。

# 載入庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler

# 載入只有兩個類別的資料
iris = datasets.load_iris()
X = iris.data[:100,:]
y = iris.target[:100]

# 標準化特徵
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 建立邏輯迴歸物件
clf = LogisticRegression(random_state=0)

# 訓練模型
model = clf.fit(X_std, y)

# 建立新的觀測
new_observation = [[.5, .5, .5, .5]]

# 預測類別
model.predict(new_observation)

# array([1]) 

# 檢視預測的概率
model.predict_proba(new_observation)

# array([[ 0.18823041,  0.81176959]]) 

大量資料上的邏輯迴歸

scikit-learn 的LogisticRegression提供了許多用於訓練邏輯迴歸的技術,稱為求解器。 大多數情況下,scikit-learn 會自動為我們選擇最佳求解器,或警告我們,你不能用求解器做一些事情。 但是,我們應該注意一個特殊情況。

雖然精確的解釋超出了本書的範圍,但隨機平均梯度下降使得我們在資料非常大時,比其他求解器更快訓練模型。 但是,對特徵尺度也非常敏感,標準化我們的特徵尤為重要。 我們可以通過設定solver ='sag'來設定我們的學習演算法來使用這個求解器。

# 載入庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler

# 載入資料
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 標準化特徵
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 建立使用 SAG 求解器的邏輯迴歸
clf = LogisticRegression(random_state=0, solver='sag')

# 訓練模型
model = clf.fit(X_std, y)

帶有 L1 正則化的邏輯迴歸

L1 正則化(也稱為最小絕對誤差)是資料科學中的強大工具。 有許多教程解釋 L1 正則化,我不會在這裡嘗試這樣做。 相反,本教程將展示正則化引數C對係數和模型精度的影響。

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

本教程中使用的資料集是著名的鳶尾花資料集。鳶尾花資料包含來自三種鳶尾花y,和四個特徵變數X的 50 個樣本。

資料集包含三個類別(三種鳶尾),但是為了簡單起見,如果目標資料是二元的,則更容易。因此,我們將從資料中刪除最後一種鳶尾。

# 載入鳶尾花資料集
iris = datasets.load_iris()

# 從特徵中建立 X
X = iris.data

# 從目標中建立 y
y = iris.target

# 重新生成變數,保留所有標籤不是 2 的資料
X = X[y != 2]
y = y[y != 2]

# 檢視特徵
X[0:5]

'''
array([[ 5.1,  3.5,  1.4,  0.2],
       [ 4.9,  3\. ,  1.4,  0.2],
       [ 4.7,  3.2,  1.3,  0.2],
       [ 4.6,  3.1,  1.5,  0.2],
       [ 5\. ,  3.6,  1.4,  0.2]]) 
'''

# 檢視目標資料
y

'''
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1]) 
'''

# 將資料拆分為測試和訓練集
# 將 30% 的樣本放入測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

因為正則化懲罰由係數的絕對值之和組成,所以我們需要縮放資料,使係數都基於相同的比例。

# 建立縮放器物件
sc = StandardScaler()

# 將縮放器擬合訓練資料,並轉換
X_train_std = sc.fit_transform(X_train)

# 將縮放器應用於測試資料
X_test_std = sc.transform(X_test)

L1 的用處在於它可以將特徵係數逼近 0,從而建立一種特徵選擇方法。 在下面的程式碼中,我們執行帶有 L1 懲罰的邏輯迴歸四次,每次都減少了C的值。 我們應該期望隨著C的減少,更多的係數變為 0。

C = [10, 1, .1, .001]

for c in C:
    clf = LogisticRegression(penalty='l1', C=c)
    clf.fit(X_train, y_train)
    print('C:', c)
    print('Coefficient of each feature:', clf.coef_)
    print('Training accuracy:', clf.score(X_train, y_train))
    print('Test accuracy:', clf.score(X_test, y_test))
    print('')

'''
C: 10
Coefficient of each feature: [[-0.0855264  -3.75409972  4.40427765  0\.        ]]
Training accuracy: 1.0
Test accuracy: 1.0

C: 1
Coefficient of each feature: [[ 0\.         -2.28800472  2.5766469   0\.        ]]
Training accuracy: 1.0
Test accuracy: 1.0

C: 0.1
Coefficient of each feature: [[ 0\.         -0.82310456  0.97171847  0\.        ]]
Training accuracy: 1.0
Test accuracy: 1.0

C: 0.001
Coefficient of each feature: [[ 0\.  0\.  0\.  0.]]
Training accuracy: 0.5
Test accuracy: 0.5 
'''

注意,當C減小時,模型係數變小(例如,從C = 10時的4.36276075變為C = 0.1時的0.0.97175097),直到C = 0.001,所有係數都是零。 這是變得更加突出的,正則化懲罰的效果。

OVR 邏輯迴歸

邏輯迴歸本身只是二分類器,這意味著它們無法處理具有兩個類別以上的目標向量。 但是,邏輯迴歸有一些聰明的擴充套件來實現它。 在 One-VS-Rest(OVR)邏輯迴歸中,針對每個類別訓練單獨的模型,預測觀測是否是該類(因此使其成為二分類問題)。 它假定每個分類問題(例如是不是類 0)是獨立的。

# 載入庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler

# 載入資料
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 標準化特徵
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 建立 OVR 邏輯迴歸物件
clf = LogisticRegression(random_state=0, multi_class='ovr')

# 訓練模型
model = clf.fit(X_std, y)

# 建立新的觀測
new_observation = [[.5, .5, .5, .5]]

# 預測類別
model.predict(new_observation)

# array([2]) 

# 檢視預測概率
model.predict_proba(new_observation)

# array([[ 0.0829087 ,  0.29697265,  0.62011865]])