【Python機器學習】102:如何使用Scikit-Learn預測器完成數值預測

Using Scikit-Learn predictor to complete numerical prediction

張育晟 Eason Chang
展開數據人生
11 min readMay 19, 2020

--

上一篇簡單介紹機器學習後,這一篇要教大家使用Python強大的Scikit-Learn,它是一個單純而且有效率的資料探勘(data mining)和資料分析(data analysis)的工具。其中,Scikit-Learn在獲取資料:sklearn.datasets掌握資料:sklearn.preprocessing 機器學習:sklearn Estimator API 三個面向提供支援。

獲取資料的方式有很多種(包含檔案、資料庫、網路爬蟲、Kaggle Datasets等),其中最簡單的方式是從Sklearn import 內建的資料庫。由於其特性隨手可得且不用下載,所以我們通常叫他玩具資料

keys
‘‘filename’’

先從datasets 使用 load_ 函數讀入一個像是dictionary的物件,像上圖中的load_boston 就有5組key-value組合。其中,‘filename’可以讓你去access這台電腦裡原始檔案的儲存位置,假如你想看一下它的原始檔案到底長什麼樣子,就可以把‘filename’秀出來。

掌握資料:Scikit-Learn表達資料的方式有分兩種:

特徵矩陣(Feature Matrix):m * n 的 ndarray

目標向量(Target Vector):m * 1 或是 (m, 1)的 ndarray

這邊將用kaggle-Getting Started 競賽的兩組訓練資料(train.csv)來示範如何擷出特徵矩陣 & 目標向量:

把 Titanic 資料讀進來之後,我們先用pandas把它轉換成表格,並用head()瀏覽表格的內容。題目告知Survived是目標向量後,我們要把這欄單獨切割出來,而表格中的其餘資料就是它的特徵矩陣。

由於目前的資料是pandas的DataFrame的型態,所以我可以直接擷取我要的欄位。但是注意:我如果直接挑選欄位名稱,出來的資料型態會是Series。所以我最後要再加 .values 把值單獨取出來,資料才會變成向量的型態,最後也別忘了要reshape成欄位為1的形式。

那剩下的資料就是我的特徵矩陣咯,所以我這邊使用drop()函數刪掉 Survived 欄位後一樣取values。這邊要注意drop函數要記得給axis參數,因為它的預設參數是0,那他就會以row去看說有沒有一個row的index叫 ‘Survived’ 的,但我們這邊是要拿掉欄位,所以要記得給axis = 1。

就這樣,簡單的特徵矩陣和目標向量就被我們手動切割出來啦。

根據監督式學習(Supervised Learning)的定義:

使用標籤資料(labelled data)訓練模型,再對無標籤資料(unlabelled data)預測

所以我們可以使用 train.csv 做訓練,然後對 test.csv做預測對吧?

是,也不是。

為什麼答案是不一定呢?因為像是Kaggle 的 Getting Started 競賽允許一天上傳多次對答案。但在生活中的專案可沒有那麼多次機會讓你嘗試,你只能訓練模型,最後一直到testing_data出來了才能去做預測,那時候才知道自己的模型做的好不好(例如:A/B Test的實驗設計)。

因此,我們因此通常會將 train.csv 再切分成為訓練資料與驗證資料兩個部分:

訓練(training)是標籤資料(labelled data)

驗證(validation)是偽裝成無標籤資料(unlabelled data)的標籤資料(labelled data)

picture from https://datascience.stackexchange.com/questions/61467/clarification-on-train-test-and-val-and-how-to-use-implement-it

Scikit-Learn這裏就提供了一個非常好用的函式:我們可以使用sklearn.model_selection中的train_test_split函數。雖然說是train-test split,但實際上是train-validation split 。

我們使用Housing資料來示範:

我們可以看到原本在切割前的資料它是有1460筆,但是在呼叫train_test_split函數後,這筆資料就被我切割成978 & 482筆。

我們再用head()看一下切割出來的資料可以發現不管是training data還是validation data都是隨機切割的。

我們簡單解釋一下train_test_split 函數到底做了哪些事情:

首先test_size=0.33是指我1/3的資料先偽裝成validation data,剩下的2/3當成training data。剛才有提到train_test_split這個函數是隨機切割資料的,也就是說我每次跑出來的validation data跟training data都不一樣。那設定random_state = 42可以確保我每次跑出來的validation data和training data就都會一樣(效果很像numpy.random中的seed)。

完整的 train_test_split 函數可以輸入 X與 y,並且分別回傳 4 個分割資料:X_train、X_validation、y_train、y_validation

我們這次就用用看最一開始提到的玩具資料來跑跑看:

平時在切割資料時是不會設定random_state參數的,這邊只是存粹為了方便。由於隨機排序的關係,訓練與驗證資料的分割會影響模型的評估指標。

把random_state參數拿掉跑跑看
得到的模型評估指標都不一樣,有好有壞

所以機器學習通常會用一個叫交叉驗證(Cross-Validation)的方式,讓所有資料都當一次驗證資料試試看。

photo from http://ethen8181.github.io/machine-learning/model_selection/model_selection.html

Example:5-fold cross validation,在k=5的設定下,我們將會把資料依據4:1的比例分割為訓練與驗證,就迭代5次且每一次都會算出一個MSE。

使用sklearn.model_selection中的KFold()函數:

如上圖:kfold函數會產生把資料平均切割成5份的index,第一次的fold:validation的index:(0-291),剩下的4份就當training,下一次fold的validation就會從index(292)開始,以此類推。

使用Kfold()函數獲得index之後在split的時候就不需要再使用train_test_split了,直接用kfold給我們的index去切割就可以了。

但是由於KFold()函數得到的只是分隔的索引值依據,CV的MSE還是得自己算,這時候可以再進階使用 sklearn.model_selection 的 cross_val_score()函數:

在使用這個函數時要注意它的評估指標不是常見的mean_squared_error,而是negative_mean_squared_error,是負的!!。

更精密的交叉驗證函數:

ShuffleSplit():在 KFold()的基礎下加入隨機排序

StratifiedKFold():在 KFold()的基礎下加入考慮類別的分層(適用於分類問題)

StratifiedShuffleSplit():在 StratifiedKFold()的基礎下加入隨機排序

改用ShuffleSplit(n_splits=5, test_size=0.2, random_state=0)各算一次mses與CV的mse
改用cross_val_score()各算一次mses與CV的mse
得到的結果相同

接下來我們來簡介Scikit-Learn機器學習的Estimator API,那什麼是Estimator呢?以大方向來講分成兩個小類別,一個叫Predictor ex:Linear Regression, Logistic Regression;另一類型叫Transformer。

完整步驟:

選擇一個Estimator:Predictor或 Transformer

初始化:預設或設定參數

準備特徵矩陣與目標向量

使用 Estimator.fit()訓練

使用 Predictor.predict()預測 / Transformer.transform()轉換

選擇Estimator(使用範例:Predictor)

初始化

準備特徵矩陣與目標向量

使用Predictor.fit()訓練

使用Predictor.predict()預測

其中,Transformer在幾次 Scikit-Learn 改版之後不需要像Predictor一樣要先呼叫fit,他可以直接呼叫fit_transform。

我們使用housing資料並將GrLvArea作為特徵矩陣、SalePrice 作為目標向量給大家示範:

範例中的Estimator我們選擇使用sklearn.linear_model中的LinearRegression這個Predictor。初始化完成之後就可以將我們的X_train和y_train fit到我們的Predictor。fit完成之後我們就有了一些屬性可以檢查,像是看截距項 & 係數。這邊要注意intercept 和 coef物件在呼叫的時候最後要加一個 _。

最後,再使用訓練出來的linear regression 針對X_validation 做預測會得到y_pred,與原本的y_validation對比,就可以算誤差值(MSE)的大小,就可以得知此模型的好壞。

感謝你閱讀完這篇文章,如果你覺得這些文章對你有幫助請在底下幫我拍個手(長按最多可以拍50下手)。

上一章:【Python機器學習】101:機器學習簡介

下一章:【Python機器學習】103:使用正規方程式解決線性 & 非線性回歸模型

--

--

張育晟 Eason Chang
展開數據人生

在不斷變動中努力思索自己的定位,想做的事情很多,但最希望的是不要變成無趣的人。 Linkedin: https://www.linkedin.com/in/stareason1997