【導包】使用Sklearn構建Logistic迴歸分類器
導包:
from sklearn.linear_model import LogisticRegression
使用:
classifier = LogisticRegression(solver='sag',max_iter=5000).fit(trainingSet, trainingLabels) classifier= LogisticRegression(引數).fit方法(trainingSet訓練集, trainingLabels標籤) #訓練集和標籤用的是列表一對一 #比如求和單數為1,雙數為0 #【【1,2,3,4,5】,【1,3,4,5,7】】 #【1,0】
需要的做的:
1.根據實際情況設定好引數
2.得到整理好的資料trainingSet訓練集和trainingLabels標籤並且與1一起得到對應模型classifier
3.對模型選擇方法,得到想要的結果
引數說明如下:
penalty:懲罰項,str型別,可選引數為l1和l2,預設為l2。用於指定懲罰項中使用的規範。newton-cg、sag和lbfgs求解演算法只支援L2規範。L1G規範假設的是模型的引數滿足拉普拉斯分佈,L2假設的模型引數滿足高斯分佈,所謂的正規化就是加上對引數的約束,使得模型更不會過擬合(overfit),但是如果要說是不是加了約束就會好,這個沒有人能回答,只能說,加約束的情況下,理論上應該可以獲得泛化能力更強的結果。
dual:對偶或原始方法,bool型別,預設為False。對偶方法只用在求解線性多核(liblinear)的L2懲罰項上。當樣本數量>樣本特徵的時候,dual通常設定為False。
tol:停止求解的標準,float型別,預設為1e-4。就是求解到多少的時候,停止,認為已經求出最優解。
c:正則化係數λ的倒數,float型別,預設為1.0。必須是正浮點型數。像SVM一樣,越小的數值表示越強的正則化。
fit_intercept:是否存在截距或偏差,bool型別,預設為True。
intercept_scaling:僅在正則化項為”liblinear”,且fit_intercept設定為True時有用。float型別,預設為1。
class_weight
那麼class_weight有什麼作用呢?
在分類模型中,我們經常會遇到兩類問題:
1.第一種是誤分類的代價很高。比如對合法使用者和非法使用者進行分類,將非法使用者分類為合法使用者的代價很高,我們寧願將合法使用者分類為非法使用者,這時可以人工再甄別,但是卻不願將非法使用者分類為合法使用者。這時,我們可以適當提高非法使用者的權重。
2.第二種是樣本是高度失衡的,比如我們有合法使用者和非法使用者的二元樣本資料10000條,裡面合法使用者有9995條,非法使用者只有5條,如果我們不考慮權重,則我們可以將所有的測試集都預測為合法使用者,這樣預測準確率理論上有99.95%,但是卻沒有任何意義。這時,我們可以選擇balanced,讓類庫自動提高非法使用者樣本的權重。提高了某種分類的權重,相比不考慮權重,會有更多的樣本分類劃分到高權重的類別,從而可以解決上面兩類問題。
random_state:隨機數種子,int型別,可選引數,預設為無,僅在正則化優化演算法為sag,liblinear時有用。
solver:優化演算法選擇引數,只有五個可選引數,即newton-cg,lbfgs,liblinear,sag,saga。預設為liblinear。solver引數決定了我們對邏輯迴歸損失函式的優化方法,有四種演算法可以選擇,分別是:
liblinear | 使用了開源的liblinear庫實現,內部使用了座標軸下降法來迭代優化損失函式。適用於小資料集 |
lbfgs | 擬牛頓法的一種,利用損失函式二階導數矩陣即海森矩陣來迭代優化損失函式。 |
newton-cg | 也是牛頓法家族的一種,利用損失函式二階導數矩陣即海森矩陣來迭代優化損失函式。 |
sag | 即隨機平均梯度下降,是梯度下降法的變種,和普通梯度下降法的區別是每次迭代僅僅用一部分的樣本來計算梯度,適合於樣本資料多的時候。 |
saga | 線性收斂的隨機優化演算法的的變重。適合於樣本資料多的時候 |
總結:
對於多分類問題,只有newton-cg,sag,saga和lbfgs能夠處理多項損失,而liblinear受限於一對剩餘(OvR)。啥意思,就是用liblinear的時候,如果是多分類問題,得先把一種類別作為一個類別,剩餘的所有類別作為另外一個類別。以此類推,遍歷所有類別,進行分類。
newton-cg,sag和lbfgs這三種優化演算法時都需要損失函式的一階或者二階連續導數,因此不能用於沒有連續導數的L1正則化,只能用於L2正則化。而liblinear和saga通吃L1正則化和L2正則化。
同時,sag每次僅僅使用了部分樣本進行梯度迭代,所以當樣本量少的時候不要選擇它,而如果樣本量非常大,比如大於10萬,sag是第一選擇。但是sag不能用於L1正則化,所以當你有大量的樣本,又需要L1正則化的話就要自己做取捨了。要麼通過對樣本取樣來降低樣本量,要麼回到L2正則化。
從上面的描述,大家可能覺得,既然newton-cg, lbfgs和sag這麼多限制,如果不是大樣本,我們選擇liblinear不就行了嘛!錯,因為liblinear也有自己的弱點!我們知道,邏輯迴歸有二元邏輯迴歸和多元邏輯迴歸。對於多元邏輯迴歸常見的有one-vs-rest(OvR)和many-vs-many(MvM)兩種。而MvM一般比OvR分類相對準確一些。鬱悶的是liblinear只支援OvR,不支援MvM,這樣如果我們需要相對精確的多元邏輯迴歸時,就不能選擇liblinear了。也意味著如果我們需要相對精確的多元邏輯迴歸不能使用L1正則化了。
max_iter:演算法收斂最大迭代次數,int型別,預設為10。僅在正則化優化演算法為newton-cg, sag和lbfgs才有用,演算法收斂的最大迭代次數。
multi_class:分類方式選擇引數,str型別,可選引數為ovr和multinomial,預設為ovr。ovr即前面提到的one-vs-rest(OvR),而multinomial即前面提到的many-vs-many(MvM)。如果是二元邏輯迴歸,ovr和multinomial並沒有任何區別,區別主要在多元邏輯迴歸上。
OvR和MvM有什麼不同?
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型別。預設為0。就是不輸出訓練過程,1的時候偶爾輸出結果,大於1,對於每個子模型都輸出。
warm_start:熱啟動引數,bool型別。預設為False。如果為True,則下一次訓練是以追加樹的形式進行(重新使用上一次的呼叫作為初始化)。
n_jobs:並行數。int型別,預設為1。1的時候,用CPU的一個核心執行程式,2的時候,用CPU的2個核心執行程式。為-1的時候,用所有CPU的核心執行程式。
LogisticRegression的一些方法:
對於每個函式的具體使用,可以看下官方文件:http://scikit-learn.org/dev/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression
程式碼示例:
# -*- coding:UTF-8 -*- from sklearn.linear_model import LogisticRegression """ 函式說明:使用Sklearn構建Logistic迴歸分類器 Parameters: 無 Returns: 無 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Zhihu: https://www.zhihu.com/people/Jack--Cui/ Modify: 2017-09-05 """ def colicSklearn(): frTrain = open('horseColicTraining.txt') #開啟訓練集 frTest = open('horseColicTest.txt') #開啟測試集 trainingSet = []; trainingLabels = [] #準備訓練資料 testSet = []; testLabels = [] #準備測試資料 for line in frTrain.readlines(): currLine = line.strip().split('\t') lineArr = [] for i in range(len(currLine)-1): lineArr.append(float(currLine[i])) trainingSet.append(lineArr) trainingLabels.append(float(currLine[-1])) for line in frTest.readlines(): currLine = line.strip().split('\t') lineArr =[] for i in range(len(currLine)-1): lineArr.append(float(currLine[i])) testSet.append(lineArr) testLabels.append(float(currLine[-1])) # classifier = LogisticRegression(solver='liblinear',max_iter=10).fit(trainingSet, trainingLabels) classifier = LogisticRegression(solver='sag',max_iter=5000).fit(trainingSet, trainingLabels) #隨機平均梯度下降(每次用一部分) test_accurcy = classifier.score(testSet, testLabels) * 100 print('正確率:%f%%' % test_accurcy) print(trainingSet) # fv=classifier.predict(testSet) # print(fv) #?? # # tg=classifier.decision_function(testSet) # print(tg) if __name__ == '__main__': colicSklearn()View Code