【Python機器學習】102:如何使用Scikit-Learn預測器完成數值預測
Using Scikit-Learn predictor to complete numerical prediction
上一篇簡單介紹機器學習後,這一篇要教大家使用Python強大的Scikit-Learn,它是一個單純而且有效率的資料探勘(data mining)和資料分析(data analysis)的工具。其中,Scikit-Learn在獲取資料:sklearn.datasets、掌握資料:sklearn.preprocessing 和 機器學習:sklearn Estimator API 三個面向提供支援。
獲取資料的方式有很多種(包含檔案、資料庫、網路爬蟲、Kaggle Datasets等),其中最簡單的方式是從Sklearn import 內建的資料庫。由於其特性隨手可得且不用下載,所以我們通常叫他玩具資料:
先從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 的目標向量為 Survived,其餘變數為特徵矩陣
- House Prices: Advanced Regression Techniques 的目標向量為 SalePrice,其餘變數為特徵矩陣
把 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)
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參數的,這邊只是存粹為了方便。由於隨機排序的關係,訓練與驗證資料的分割會影響模型的評估指標。
所以機器學習通常會用一個叫交叉驗證(Cross-Validation)的方式,讓所有資料都當一次驗證資料試試看。
Example:5-fold cross validation,在k=5的設定下,我們將會把資料依據4:1的比例分割為訓練與驗證,就迭代5次且每一次都會算出一個MSE。
使用sklearn.model_selection中的KFold()函數:
使用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()的基礎下加入隨機排序
接下來我們來簡介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下手)。