Python機器學習庫Sklearn系列教程(14)-邏輯迴歸

引數

penalty : str, ‘l1’ or ‘l2’

LogisticRegression和LogisticRegressionCV預設就帶了正則化項。penalty引數可選擇的值為“l1”和“l2”,分別對應L1的正則化和L2的正則化,預設是L2的正則化。

在調參時如果我們主要的目的只是為了解決過擬合,一般penalty選擇L2正則化就夠了。但是如果選擇L2正則化發現還是過擬合,即預測效果差的時候,就可以考慮L1正則化。

另外,如果模型的特徵非常多,我們希望一些不重要的特徵係數歸零,從而讓模型係數稀疏化的話,也可以使用L1正則化。

penalty引數的選擇會影響我們損失函式最佳化演算法的選擇。即引數solver的選擇,如果是L2正則化,那麼4種可選的演算法{‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可以選擇。

但是如果penalty是L1正則化的話,就只能選擇‘liblinear’了。這是因為L1正則化的損失函式不是連續可導的,而{‘newton-cg’, ‘lbfgs’,‘sag’}這三種最佳化演算法時都需要損失函式的一階或者二階連續導數。而‘liblinear’並沒有這個依賴。

dual : bool

對偶或者原始方法。Dual只適用於正則化相為l2 liblinear的情況,通常樣本數大於特徵數的情況下,預設為False

tol : float, optional

迭代終止判據的誤差範圍。

C : float, default: 1。0

C為正則化係數λ的倒數,通常預設為1。設定越小則對應越強的正則化。

fit_intercept : bool, default: True

是否存在截距,預設存在

intercept_scaling : float, default 1。

僅在正則化項為“liblinear”,且fit_intercept設定為True時有用。

class_weight : dict or ‘balanced’, default: None

class_weight引數用於標示分類模型中各種型別的權重,可以不輸入,即不考慮權重,或者說所有型別的權重一樣。如果選擇輸入的話,可以選擇balanced讓類庫自己計算型別權重,

或者我們自己輸入各個型別的權重,比如對於0,1的二元模型,我們可以定義class_weight={0:0。9, 1:0。1},這樣型別0的權重為90%,而型別1的權重為10%。

如果class_weight選擇balanced,那麼類庫會根據訓練樣本量來計算權重。某種型別樣本量越多,則權重越低;樣本量越少,則權重越高。

當class_weight為balanced時,類權重計算方法如下:n_samples / (n_classes * np。bincount(y))

n_samples為樣本數,n_classes為類別數量,np。bincount(y)會輸出每個類的樣本數,例如y=[1,0,0,1,1],則np。bincount(y)=[2,3] 0,1分別出現2次和三次

那麼class_weight有什麼作用呢?

在分類模型中,我們經常會遇到兩類問題:

第一種是誤分類的代價很高。比如對合法使用者和非法使用者進行分類,將非法使用者分類為合法使用者的代價很高,我們寧願將合法使用者分類為非法使用者,這時可以人工再甄別,但是卻不願將非法使用者分類為合法使用者。這時,我們可以適當提高非法使用者的權重。

第二種是樣本是高度失衡的,比如我們有合法使用者和非法使用者的二元樣本資料10000條,裡面合法使用者有9995條,非法使用者只有5條,如果我們不考慮權重,則我們可以將所有的測試集都預測為合法使用者,這樣預測準確率理論上有99。95%,但是卻沒有任何意義。

這時,我們可以選擇balanced,讓類庫自動提高非法使用者樣本的權重。

random_state : int, RandomState instance or None, optional, default: None

隨機數種子,預設為無,僅在正則化最佳化演算法為sag,liblinear時有用。

solver : {‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’}

solver引數決定了我們對邏輯迴歸損失函式的最佳化方法,有4種演算法可以選擇,分別是:

a) liblinear:使用了開源的liblinear庫實現,內部使用了座標軸下降法來迭代最佳化損失函式。

b) lbfgs:擬牛頓法的一種,利用損失函式二階導數矩陣即海森矩陣來迭代最佳化損失函式。

c) newton-cg:也是牛頓法家族的一種,利用損失函式二階導數矩陣即海森矩陣來迭代最佳化損失函式。

d) sag:即隨機平均梯度下降,是梯度下降法的變種,和普通梯度下降法的區別是每次迭代僅僅用一部分的樣本來計算梯度,適合於樣本資料多的時候,SAG是一種線性收斂演算法,這個速度遠比SGD快。

從上面的描述可以看出,newton-cg, lbfgs和sag這三種最佳化演算法時都需要損失函式的一階或者二階連續導數,因此不能用於沒有連續導數的L1正則化,只能用於L2正則化。而liblinear則既可以用L1正則化也可以用L2正則化。

同時,sag每次僅僅使用了部分樣本進行梯度迭代,所以當樣本量少的時候不要選擇它,而如果樣本量非常大,比如大於10萬,sag是第一選擇。但是sag不能用於L1正則化,所以當你有大量的樣本,又需要L1正則化的話就要自己做取捨了

max_iter : int, optional

僅在正則化最佳化演算法為newton-cg, sag and lbfgs 才有用,演算法收斂的最大迭代次數。

multi_class : str, {‘ovr’, ‘multinomial’}, default: ‘ovr’

OvR的思想很簡單,無論你是多少元邏輯迴歸,我們都可以看做二元邏輯迴歸。具體做法是,對於第K類的分類決策,我們把所有第K類的樣本作為正例,除了第K類樣本以外的所有樣本都作為負例,然後在上面做二元邏輯迴歸,得到第K類的分類模型。

其他類的分類模型獲得以此類推。

而MvM則相對複雜,這裡舉MvM的特例one-vs-one(OvO)作講解。如果模型有T類,我們每次在所有的T類樣本里面選擇兩類樣本出來,不妨記為T1類和T2類,把所有的輸出為T1和T2的樣本放在一起,把T1作為正例,T2作為負例,進行二元邏輯迴歸,

得到模型引數。我們一共需要T(T-1)/2次分類。

可以看出OvR相對簡單,但分類效果相對略差(這裡指大多數樣本分佈情況,某些樣本分佈下OvR可能更好)。而MvM分類相對精確,但是分類速度沒有OvR快。如果選擇了ovr,則4種損失函式的最佳化方法liblinear,newton-cg,lbfgs和sag都可以選擇。

但是如果選擇了multinomial,則只能選擇newton-cg, lbfgs和sag了。

verbose : int, default: 0

warm_start : bool, default: False

n_jobs : int, default: 1

如果multi_class =‘ovr’“,並行數等於CPU核心數量。當“solver”設定為“liblinear”時,無論是否指定“multi_class”,該引數將被忽略。如果給定值-1,則使用所有核心。

這裡只講述sklearn中如何使用邏輯迴歸進行分類預測。包含2種分類結果

# -*- coding: UTF-8 -*-import numpy as np # 快速操作結構陣列的工具import pandas as pd # 資料分析處理工具# 樣本資料集,第一列為x1,第二列為x2,第三列為分類(二種類別)data=[ [-0。017612,14。053064,0], [-1。395634,4。662541,1], [-0。752157,6。538620,0], [-1。322371,7。152853,0], [0。423363,11。054677,0], [0。406704,7。067335,1], [0。667394,12。741452,0], [-2。460150,6。866805,1], [0。569411,9。548755,0], [-0。026632,10。427743,0], [0。850433,6。920334,1], [1。347183,13。175500,0], [1。176813,3。167020,1], [-1。781871,9。097953,0], [-0。566606,5。749003,1], [0。931635,1。589505,1], [-0。024205,6。151823,1], [-0。036453,2。690988,1], [-0。196949,0。444165,1], [1。014459,5。754399,1]]#生成X和y矩陣dataMat = np。mat(data)y = dataMat[:,2] # 類別變數b = np。ones(y。shape) # 新增全1列向量代表b偏量X = np。column_stack((b, dataMat[:,0:2])) # 特徵屬性集和b偏量組成xX = np。mat(X)# 特徵資料歸一化# import sklearn。preprocessing as preprocessing #sk的去均值和歸一化# scaler=preprocessing。StandardScaler()# X = scaler。fit_transform(X) # 對特徵資料集去均值和歸一化,可以加快機器效能# X = np。mat(X)# # print(X)# ========邏輯迴歸========from sklearn import metricsfrom sklearn。linear_model import LogisticRegressionmodel = LogisticRegression()model。fit(X, y)print(‘邏輯迴歸模型:\n’,model)# 使用模型預測predicted = model。predict(X) #預測分類answer = model。predict_proba(X) #預測分類機率print(answer)import matplotlib。pyplot as plt# 繪製邊界和散點# 先產生x1和x2取值範圍上的網格點,並預測每個網格點上的值。h = 0。02x1_min, x1_max = X[:,1]。min() - 。5, X[:,1]。max() + 。5x2_min, x2_max = X[:,2]。min() - 。5, X[:,2]。max() + 。5xx1, xx2 = np。meshgrid(np。arange(x1_min, x1_max, h), np。arange(x2_min, x2_max, h))testMat = np。c_[xx1。ravel(), xx2。ravel()] #形成測試特徵資料集testMat = np。column_stack((np。ones(((testMat。shape[0]),1)),testMat)) #新增第一列為全1代表b偏量testMat = np。mat(testMat)Z = model。predict(testMat)# 繪製區域網格圖Z = Z。reshape(xx1。shape)plt。pcolormesh(xx1, xx2, Z, cmap=plt。cm。Paired)# 繪製散點圖 引數:x橫軸 y縱軸,顏色代表分類。x圖示為樣本點,。表示預測點plt。scatter(X[:,1]。flatten()。A[0], X[:,2]。flatten()。A[0],c=y。flatten()。A[0],marker=‘x’) # 繪製樣本資料集plt。scatter(X[:,1]。flatten()。A[0], X[:,2]。flatten()。A[0],c=predicted。tolist(),marker=‘。’) # 繪製預測資料集# 繪製x軸和y軸座標plt。xlabel(“x”)plt。ylabel(“y”)# 顯示圖形plt。show()

輸出結果為如下矩陣,第一列表示物件屬於分類1的機率,第2列表示物件屬於分類2的機率

[[ 0。95516819 0。04483181][ 0。22866334 0。77133666][ 0。39179119 0。60820881][ 0。49491521 0。50508479][ 0。81868509 0。18131491][ 0。39458788 0。60541212][ 0。90687605 0。09312395][ 0。52035976 0。47964024][ 0。6779141 0。3220859 ][ 0。7854767 0。2145233 ][ 0。35582843 0。64417157][ 0。91239261 0。08760739][ 0。07671224 0。92328776][ 0。73553143 0。26446857][ 0。29669744 0。70330256][ 0。03904873 0。96095127][ 0。31388094 0。68611906][ 0。07853207 0。92146793][ 0。02871742 0。97128258][ 0。2323216 0。7676784 ]]

輸出結果圖為

Python機器學習庫Sklearn系列教程(14)-邏輯迴歸

根據分類機率和分類圖可以看出

大體上滿足分類需求,但是由於資料量少導致會有部分中間節點的分類錯誤,分類機率差別不明顯。

我們再來看看sklear使用邏輯分類實現多分類,仍然使用上面的函式。

將資料集data換成

data=[ [-2。68420713, 0。32660731, 0],[-2。71539062, -0。16955685, 0],[-2。88981954, -0。13734561, 0],[-2。7464372, -0。31112432, 0],[-2。72859298, 0。33392456, 0], [-2。27989736, 0。74778271, 0],[-2。82089068, -0。08210451, 0],[-2。62648199, 0。17040535, 0],[-2。88795857, -0。57079803, 0],[-2。67384469, -0。1066917, 0], [-2。50652679,0。65193501,0],[-2。61314272,0。02152063,0],[-2。78743398,-0。22774019,0],[-3。22520045,-0。50327991,0],[-2。64354322,1。1861949,0], [-2。38386932,1。34475434,0],[-2。6225262,0。81808967,0],[-2。64832273,0。31913667,0],[-2。19907796,0。87924409,0],[-2。58734619,0。52047364,0], [1。28479459, 0。68543919, 1],[0。93241075, 0。31919809, 1],[1。46406132, 0。50418983, 1],[0。18096721, -0。82560394, 1],[1。08713449, 0。07539039, 1], [0。64043675, -0。41732348, 1],[1。09522371, 0。28389121, 1],[-0。75146714, -1。00110751, 1],[1。04329778, 0。22895691, 1],[-0。01019007, -0。72057487, 1], [-0。5110862,-1。26249195,1],[0。51109806,-0。10228411,1],[0。26233576,-0。5478933,1],[0。98404455,-0。12436042,1],[-0。174864,-0。25181557,1], [0。92757294,0。46823621,1],[0。65959279,-0。35197629,1],[0。23454059,-0。33192183,1],[0。94236171,-0。54182226,1],[0。0432464,-0。58148945,1], [2。53172698, -0。01184224, 2],[1。41407223, -0。57492506, 2],[2。61648461, 0。34193529, 2],[1。97081495, -0。18112569, 2],[2。34975798, -0。04188255, 2], [3。39687992, 0。54716805, 2],[0。51938325, -1。19135169, 2],[2。9320051, 0。35237701, 2],[2。31967279, -0。24554817, 2],[2。91813423, 0。78038063, 2], [1。66193495,0。2420384,2],[1。80234045,-0。21615461,2],[2。16537886,0。21528028,2],[1。34459422,-0。77641543,2],[1。5852673,-0。53930705,2], [1。90474358,0。11881899,2],[1。94924878,0。04073026,2],[3。48876538,1。17154454,2],[3。79468686,0。25326557,2],[1。29832982,-0。76101394,2],

Python機器學習庫Sklearn系列教程(14)-邏輯迴歸