天天看點

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

用Python建立機器學習模型,得益于Python生态下的包共享機制,機器模型建構的過程其實已經變得非常簡單了,很多聽起來牛逼的算法,其實根本不需要自己實作,甚至都不需要知道這些算法的具體原理。

你隻需要兩步就能建構起自己的機器學習模型:

  1. 明确你需要解決的問題是什麼類型,以及知道解決該類型問題所對應的算法。
  2. 從skicit-learn中調用相應的算法構模組化型即可。是的!在機器學習領域,如果你隻是抱着體驗機器學習的心态,實作起來就是這麼簡單。

第一步很好解決

常見的問題類型隻有三種:分類、回歸、聚類。而明确具體問題對應的類型也很簡單。比如,如果你需要通過輸入資料得到一個類别變量,那就是分類問題。分成兩類就是二分類問題,分成兩類以上就是多分類問題。常見的有:判别一個郵件是否是垃圾郵件、根據圖檔分辯圖檔裡的是貓還是狗等等。

如果你需要通過輸入資料得到一個具體的連續數值,那就是回歸問題。比如:預測某個區域的房價等。

常用的分類和回歸算法算法有:SVM (支援向量機) 、xgboost、, KNN、LR算法、SGD (随機梯度下降算法)、Bayes (貝葉斯估計)以及随機森林等。這些算法大多都既可以解分類問題,又可以解回歸問題。

如果你的資料集并沒有對應的屬性标簽,你要做的,是發掘這組樣本在空間的分布, 比如分析哪些樣本靠的更近,哪些樣本之間離得很遠, 這就是屬于聚類問題。常用的聚類算法有k-means算法。

在本文中,我們主要解決第二步:通過skicit-learn構模組化型。告訴你你一套讓你簡單到想笑的通用模型構模組化闆。隻要scikit-learn實作的算法,都可以通過這種方式快速調用。牢記這三個萬能模闆,你就能輕松建構起自己的機器學習模型。

預備工作

在介紹萬能模闆之前,為了能夠更深刻地了解這三個模闆,我們加載一個Iris(鸢尾花)資料集來作為應用萬能模闆的小例子,Iris資料集在前邊的文章中已經提到過多次了,這裡不再贅述。它是一個典型的多分類問題。加載步驟如下:

1、加載資料集

因為原始的資料集中包含很多空值,而且類别特征用英文名表示各個花的名字,也需要我們轉換成數字。

在scikit-learn下的datasets子包裡,也自帶了一個Iris資料集,這個資料集和原始資料集的差別就是scikit-learn已經幫我們提前處理好了空值等問題,可以直接輸入模型用來訓練。是以為了友善起見,我們直接使用scikit-learn的資料集。加載方法如下:

from sklearn.datasets import load_iris
data = load_iris()
x = data.data
y = data.target      

x值如下,可以看到scikit-learn把資料集經過去除空值處理放在了array裡,是以x是一個(150,4)的數組,儲存了150個資料的4個特征:

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], [5.4, 3.9, 1.7, 0.4], [4.6, 3.4, 1.4, 0.3], [5. , 3.4, 1.5, 0.2], [4.4, 2.9, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1], [5.4, 3.7, 1.5, 0.2], [4.8, 3.4, 1.6, 0.2], [4.8, 3. , 1.4, 0.1], [4.3, 3. , 1.1, 0.1], …………

y值如下,共有150行,其中0、1、2分别代表三類花:

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, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

2、資料集拆分

資料集拆分是為了驗證模型在訓練集和測試集是否過拟合,使用​

​train_test_split​

​的目的是保證從資料集中均勻拆分出測試集。這裡,簡單把10%的資料集拿出來用作測試集。

from sklearn.model_selection import train_test_split
train_x,test_x,train_y,test_y = train_test_split(x,y,test_size=0.1,random_state=0)      

萬能模闆V1.0版

助你快速建構一個基本的算法模型

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

不同的算法隻是改變了名字,以及模型的參數不同而已。

有了這個萬能模闆,接下來就是簡單的複制粘貼改名字了:

而且在scikit-learn中,每個包的位置都是有規律的,比如:随機森林就是在內建學習檔案夾下。

模闆1.0應用案例

1、建構SVM分類模型

通過查閱資料,我們知道svm算法在​

​scikit-learn.svm.SVC​

​下,是以:

  1. 算法位置填入:​

    ​svm​

  2. 算法名填入:​

    ​SVC()​

  3. 模型名自己起,這裡我們就叫​

    ​svm_model​

套用模闆得到程式如下:

# svm分類器

from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

svm_model = SVC()

svm_model.fit(train_x,train_y)

pred1 = svm_model.predict(train_x)
accuracy1 = accuracy_score(train_y,pred1)
print('在訓練集上的精确度: %.4f'%accuracy1)

pred2 = svm_model.predict(test_x)
accuracy2 = accuracy_score(test_y,pred2)
print('在測試集上的精确度: %.4f'%accuracy2)      

輸出:

在訓練集上的精确度: 0.9810

在測試集上的精确度: 0.9778

2、建構LR分類模型

同理,找到LR算法在​

​sklearn.linear_model.LogisticRegression​

​下,是以:

  1. 算法位置填入:​

    ​linear_model​

  2. 算法名填入:​

    ​LogisticRegression​

  3. 模型名叫做:lr_model。

程式如下:

套用模闆得到程式如下:

# LogisticRegression分類器

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score #評分函數用精确度評估

lr_model = LogisticRegression()

lr_model.fit(train_x,train_y)

pred1 = lr_model.predict(train_x)
accuracy1 = accuracy_score(train_y,pred1)
print('在訓練集上的精确度: %.4f'%accuracy1)

pred2 = lr_model.predict(test_x)
accuracy2 = accuracy_score(test_y,pred2)
print('在測試集上的精确度: %.4f'%accuracy2)      

輸出:

在訓練集上的精确度: 0.9429

在測試集上的精确度: 0.8889

3、建構随機森林分類模型

随機森林算法在​

​sklearn.ensemble.RandomForestClassifier​

​ 下,好了,現在你應該可以自己寫了,這個作為本文的一個小測試,歡迎在評論區寫下你的答案。

萬能模闆V2.0版

加入交叉驗證,讓算法模型評估更加科學

在1.0版的模闆中,當你多次運作同一個程式就會發現:每次運作得到的精确度并不相同,而是在一定範圍内浮動,這是因為資料輸入模型之前會進行選擇,每次訓練時資料輸入模型的順序都不一樣。是以即使是同一個程式,模型最後的表現也會有好有壞。

更糟糕的是,有些情況下,在訓練集上,通過調整參數設定使模型的性能達到了最佳狀态,但在測試集上卻可能出現過拟合的情況。這個時候,我們在訓練集上得到的評分不能有效反映出模型的泛化性能。

為了解決上述兩個問題,還應該在訓練集上劃分出驗證集(validation set)并結合交叉驗證來解決。首先,在訓練集中劃分出不參與訓練的驗證集,隻是在模型訓練完成以後對模型進行評估,接着再在測試集上進行最後的評估。

但這樣大大減少了可用于模型學習的樣本數量,是以還需要采用交叉驗證的方式多訓練幾次。比如說最常用的k-折交叉驗證如下圖所示,它主要是将訓練集劃分為 k 個較小的集合。然後将k-1份訓練子集作為訓練集訓練模型,将剩餘的 1 份訓練集子集作為驗證集用于模型驗證。這樣需要訓練k次,最後在訓練集上的評估得分取所有訓練結果評估得分的平均值。

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

這樣一方面可以讓訓練集的所有資料都參與訓練,另一方面也通過多次計算得到了一個比較有代表性的得分。唯一的缺點就是計算代價很高,增加了k倍的計算量。

原理就是這樣,但理想很豐滿,現實很骨幹。在自己實作的時候卻有一個很大的難題擺在面前:怎麼能夠把訓練集均勻地劃分為K份?

這個問題不用思考太多,既然别忘了,我們現在是站在巨人的肩膀上,scikit-learn已經将優秀的數學家所想到的均勻拆分方法和程式員的智慧融合在了​

​cross_val_score()​

​ 這個函數裡了,隻需要調用該函數即可,不需要自己想什麼拆分算法,也不用寫for循環進行循環訓練。

萬能模闆2.0如下:

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

把模型、資料、劃分驗證集的個數一股腦輸入函數,函數會自動執行上邊所說的過程。

在求精确度的時候,我們可以簡單地輸出平均精确度:

# 輸出精确度的平均值
# print("訓練集上的精确度: %0.2f " % scores1.mean())      

但是既然我們進行了交叉驗證,做了這麼多計算量,單求一個平均值還是有點浪費了,可以利用下邊代碼捎帶求出精确度的置信度:

# 輸出精确度的平均值和置信度區間
print("訓練集上的平均精确度: %0.2f (+/- %0.2f)" % (scores2.mean(), scores2.std() * 2))      

模闆2.0應用案例:

1、建構SVM分類模型

程式如下:

### svm分類器

from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC

svm_model = SVC()
svm_model.fit(train_x,train_y)

scores1 = cross_val_score(svm_model,train_x,train_y,cv=5, scoring='accuracy')
# 輸出精确度的平均值和置信度區間
print("訓練集上的精确度: %0.2f (+/- %0.2f)" % (scores1.mean(), scores1.std() * 2))

scores2 = cross_val_score(svm_model,test_x,test_y,cv=5, scoring='accuracy')
# 輸出精确度的平均值和置信度區間
print("測試集上的平均精确度: %0.2f (+/- %0.2f)" % (scores2.mean(), scores2.std() * 2))


print(scores1)
print(scores2)      

輸出:

訓練集上的精确度: 0.97 (+/- 0.08)

測試集上的平均精确度: 0.91 (+/- 0.10)

[1. 1. 1. 0.9047619 0.94736842]

[1. 0.88888889 0.88888889 0.875 0.875 ]

2、建構LR分類模型

# LogisticRegression分類器

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression


lr_model = LogisticRegression()
lr_model.fit(train_x,train_y)

scores1 = cross_val_score(lr_model,train_x,train_y,cv=5, scoring='accuracy')
# 輸出精确度的平均值和置信度區間
print("訓練集上的精确度: %0.2f (+/- %0.2f)" % (scores1.mean(), scores1.std() * 2))

scores2 = cross_val_score(lr_model,test_x,test_y,cv=5, scoring='accuracy')
# 輸出精确度的平均值和置信度區間
print("測試集上的平均精确度: %0.2f (+/- %0.2f)" % (scores2.mean(), scores2.std() * 2))

print(scores1)
print(scores2)      

輸出:

訓練集上的精确度: 0.94 (+/- 0.07)

測試集上的平均精确度: 0.84 (+/- 0.14)

[0.90909091 1. 0.95238095 0.9047619 0.94736842]

[0.90909091 0.88888889 0.88888889 0.75 0.75 ]

随機森林依舊留作小測試。

注: 如果想要一次性評估多個名額,也可以使用可以一次性輸入多個評估名額的 ​

​cross_validate()​

​函數。

三、萬能模闆V3.0版

調參讓算法表現更上一層樓

以上都是通過算法的預設參數來訓練模型的,不同的資料集适用的參數難免會不一樣,自己設計算法是設計不來的,隻能調調參這樣子,調參,是廣大算法工程師最後的尊嚴。再說,若是做算法不調參,豈不是辱沒了算法工程師在江湖上大名鼎鼎的“煉丹工程師”的名聲?

scikit-learn對于不同的算法也提供了不同的參數可以自己調節。如果細說起來,又能寫好幾篇文章,本文目的是建構一個萬能算法架構構模組化闆,是以,這裡隻介紹一下一個通用的自動化調參方法,至于更細節的每個算法對應參數的含義以及手動調參方法,會在以後的文章中結合執行個體具體慢慢介紹。

首先要明确的是,scikit-learn提供了​

​算法().get_params()​

​方法來檢視每個算法可以調整的參數,比如說,我們想檢視SVM分類器算法可以調整的參數,可以:

SVC().get_params()      

輸出的就是SVM算法可以調節的參數以及系統預設的參數值。每個參數的具體含義會在以後的文章中介紹。

{'C': 1.0,

'cache_size': 200,

'class_weight': None,

'coef0': 0.0,

'decision_function_shape': 'ovr',

'degree': 3,

'gamma': 'auto',

'kernel': 'rbf',

'max_iter': -1,

'probability': False,

'random_state': None,

'shrinking': True,

'tol': 0.001,

'verbose': False}

接着,就可以引出我們的V3.0版萬能模闆了。

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

參數的形式如下:

機器學習入門必備,使用 scikit-learn 構模組化型的萬能模闆!

程式就會按照順序測試這幾個參數的組合效果,根本不需要自己辛辛苦苦實作。寫到這裡,感謝各為大佬編寫了scikit-learn這麼友善的機器學習包。忽然就想到了一句話:哪有什麼歲月靜好,隻是因為有人替你負重前行。

看到這裡,可能有人會有疑惑:為什麼要采用清單、字典、清單三層嵌套的方式呢?params直接是字典的形式不行嗎?答案是:行,但是不好。

讓我們先算一個小的數學題:假如我們要調節n個參數,每個參數有4個備選值。那麼程式就會訓練  。當n為10的時候, ,這是一個對于計算機來說龐大的計算量。而當我們将這10個參數拆分成5組,每次隻調節兩個參數,其他參數采用預設值,那麼計算量就是  ,計算量會大大減少。

清單的作用這是如此,保證了每次隻調節清單中的一個字典中的參數。

運作之後,​

​best_model​

​就是我們得到的最優模型,可以利用這個模型進行預測。

當然,​

​best_model​

​ 還有好多好用的屬性:

  • ​best_model.cv_results_​

    ​:可以檢視不同參數情況下的評價結果。
  • ​best_model.param_​

    ​ :得到該模型的最優參數
  • ​best_model.best_score_​

    ​: 得到該模型的最後評分結果

模闆3.0應用案例

實作SVM分類器

###1、svm分類器
from sklearn.model_selection import cross_val_score,GridSearchCV
from sklearn.svm import SVC

svm_model = SVC()

params = [
        {'kernel': ['linear'], 'C': [1, 10, 100, 100]},
        {'kernel': ['poly'], 'C': [1], 'degree': [2, 3]},
        {'kernel': ['rbf'], 'C': [1, 10, 100, 100], 'gamma':[1, 0.1, 0.01, 0.001]}
        ]


best_model = GridSearchCV(svm_model, param_grid=params,cv = 5,scoring = 'accuracy')
best_model.fit(train_x,train_y)      

1)檢視最優得分:

best_model.best_score_      

輸出:

0.9714285714285714

2)檢視最優參數:

best_model.best_params_      

輸出:

{'C': 1, 'kernel': 'linear'}

3)檢視最優模型的所有參數:

best_model.best_estimator_      

這個函數會顯示出沒有調參的參數,便于整體檢視模型的參數。

4)檢視每個參數的交叉驗證結果:

best_model.cv_results_      
注:
1、以前版本是best_model.grid_scores_,現在已經移除
2、這個函數輸出很多資料,不友善檢視,一般不用      

在實際使用中,如果計算資源夠用,一般采用第三種萬能公式。如果,為了節約計算資源盡快算出結果,也會采用以後介紹的手動調參方式。

當然,本文為了說明萬能模闆的使用方法,在Iris資料集上将所有算法都實作了一遍,在實際應用中,如果項目時間緊急,根據自己的需求和資料量級選擇一個合适的算法使用即可。具體怎麼選擇,scikit-learn官方非常貼心地畫了一個圖,供大家根據資料量和算法類型選擇合适的模型,這副圖建議收藏: