2021年10月8日 星期五

機器學習筆記 : 初探 scikit-learn 套件

雖然深度學習是機器學習裡最受重視的項目, 但有些任務並不一定要用到深度學習, 利用傳統的機器學習套件 scikit-learn 就能取得很好的表現. 在進入深度學習領域之前先熟悉 scikit-lean 會比較好. 本篇是閱讀下列幾本書關於 scikit-learn 的筆記 : 
其中 No.2 是 No.7 的中譯本. 

Scikit-learn 是一個基於 Numpy 與 Scipy 的 Python 開放原始碼機器學習套件, 它實作了幾乎所有的主流機器學習演算法, 包含分類, 回歸, 分群, 降維, 隨機森林, 支持向量機, KNN, K-means 等, 並提供了資料預處理, 特徵提取, 超參數最佳化, 以及模型評估等所需的函數模組, 自 2007 年發布以來已經成為最受歡迎的機器學習套件之一. 

Scikit-learn 源自 David Cournapeau 的 Google 程式專案比賽作品 scikits.learn, 後來經過其他貢獻者例如 Fabian Pedregosa 等人重寫成為今日之面貌. 其名稱源自於原作者最初是將其視為 Scipy 的機器學習擴充工具箱 (extension toolkit), 參考 :


Scikit-learn 教學文件參考 :


Scikit-learn 套件沒有自訂資料類別, 完全使用 Python 本身的資料結構與 Numpy 陣列, 並在其所有實作的演算法中提供了一致的呼叫介面, 只要修改幾行程式碼即可用來對不同的演算法進行實驗, 因此非常容易使用 (easy to use), . 

Scikit-learn 還自帶了許多資料集, sklearn.datasets 模組提供了 load_xxxx() 函數來載入這些已清理過的玩具資料集 (toy datasets), 讓使用者能馬上用它們來進行測試與學習. 透過 fetch_xxxx() 函數則可以擷取真實資料集 (real datasets), 這樣一來使用者即可專注於演算法而無須花費時間去收集與清洗資料. 不過, Scikit-learn 並不支援分散式運算, 故不適合用來處理超大型資料集. 另一個缺點是它不支援深度學習. 

Scikit-learn 的功能與應用如下 :
  • 資料預處理 (preprocessing)
  • 模型選擇 (model selection)
  • 監督式學習 (supervised learning)
    • 分類 (classification)-離散特徵
    • 回歸 (regressing)-連續特徵
  • 非監督式學習 (unsupervised learning)
    • 分群 (clustering)
    • 降維 (dimensionality reduction)
資料預處理包含資料清洗與資料轉換, 資料清洗主要是將原始資料轉成結構化資料 (通常是指二維表格資料), 包含遺漏值處理與資料整併等, 通常使用 Pandas 套件處理. 資料轉換則是將清洗過的資料轉成適合機器學習演算法操作的格式, 例如尺規 (scale) 轉換或正規化 (normalization) 轉換, 以便演算法能達到最佳表現. 

完成資料預處理後應該對資料進行探索以便選擇一個適合的機器學習模型 (即演算法), 因為不同的任務會因為選擇的機器學習模型而有不同的預測表現. 然後即可用監督式與非監督式學習進行訓練與預測, 這兩個就是 scikit-learn 的預測器功能. Scikit-learn 的 pipeline.Pipeline 類別提供了模組化功能, 可將轉換器與預測器打包成一個任務管線 (pipeline), 並使用預設的初始化參數讓轉換與預測一氣呵成. 

在 Scikit-learn 官網有一張圖清楚地揭示使用 sklearn 進行機器學習專案的路徑 :



Source : Scikit-learn


原圖網址 :


以下是簡單的初步測試 : 


1. 安裝 Scikit-learn :    

在 Windows 下直接用 pip/pip3 指令即可安裝 Scikit-learn :

pip install -U scikit-learn    

在 Ubuntu Linux 可用 apt 指令安裝 : 

$ sudo apt install python-scikits-learn   

也可以直接使用 Google 雲端硬碟上的 Colab 功能, 這樣就完全不用安裝任何套件, 只要用瀏覽器即可馬上進行測試, Google Colab 平台上所有機器學習工具一應俱全, 且是最新版本, 參考 :



2. 匯入 sklearn 套件 : 

雖然安裝時名稱為 scikit-learn, 但此名稱不符合 Python 套件規範, 使用時真正要匯入的套件名稱是 sklean, 可用 __verion__ 屬性檢視版本, 用 __file__ 屬性可檢查 sklearn 的安裝路徑 : 

>>> import sklearn    
>>> sklearn.__version__     
'0.20.2'    
>>> sklearn.__file__   
'C:\\Python37\\lib\\site-packages\\sklearn\\__init__.py'

但實際在使用 scikit-learn 時通常不這樣匯入整個套件, 而是用 from sklearn import xxxx 匯入特定的模組, 例如 : 

from sklearn.preprocessing import PolynomialFeatures 
from sklearn.preprocessing import StandardScaler 
from sklearn.linear_model import LinearRegression 
from sklearn.linear_model import Ridge 
from sklearn.linear_model import LogisticRegression 
from sklearn.svm import SVC 
from sklearn.pipeline import Pipeline 
from sklearn.model_selection import train_test_split 
from sklearn.metrics import mean_squared_error 
from sklearn.metrics import accuracy_score

上面這些就是 scikit-learn 常用的機器學習模組. 


3. 檢視 sklearn 內建的資料集 :   

Scikit-learn 套件的 datasets 模組中內建了非常豐富的資料集, 並提供一致的 load_xxxx() 函數用來載入資料集 xxxx. 以下程式碼用來檢視 datasets 裡面內建了有哪些資料集 : 

>>> from sklearn import datasets     # 匯入 datasets 模組
>>> lists=dir(datasets)                        # dir() 會傳回模組中全部成員名稱之串列
>>> for e in lists:                                  # 用迴圈走訪串列
    if e.startswith('load'):                       # 只顯示 'load' 開頭的成員
        print(e)     
      
load_boston
load_breast_cancer
load_diabetes
load_digits
load_files
load_iris
load_linnerud
load_mlcomp
load_sample_image
load_sample_images
load_svmlight_file
load_svmlight_files
load_wine

可見總共內建了 13 套玩具資料集, 包含知名的鳶尾花 (iris), 波士頓房地產 (boston) 等資料集. 例如呼叫 load_digits() 可載入手寫數字資料集 :

>>> digits=datasets.load_digits()      
>>> digits   
{'data': array([[ 0.,  0.,  5., ...,  0.,  0.,  0.],
       [ 0.,  0.,  0., ..., 10.,  0.,  0.],
       [ 0.,  0.,  0., ..., 16.,  9.,  0.],
       ........
       [ 0.,  0.,  2., ..., 12.,  0.,  0.],
       [ 0.,  0., 10., ..., 12.,  1.,  0.]]), 
  'target': array([0, 1, 2, ..., 8, 9, 8]), 
  'target_names': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 
  'images': array([[[ 0.,  0.,  5., ...,  1.,  0.,  0.],
        [ 0.,  0., 13., ..., 15.,  5.,  0.],
        [ 0.,  3., 15., ..., 11.,  8.,  0.],
        ...,
>>> digits.data[0]    
array([ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.,  0.,  0., 13., 15., 10.,
       15.,  5.,  0.,  0.,  3., 15.,  2.,  0., 11.,  8.,  0.,  0.,  4.,
       12.,  0.,  0.,  8.,  8.,  0.,  0.,  5.,  8.,  0.,  0.,  9.,  8.,
        0.,  0.,  4., 11.,  0.,  1., 12.,  7.,  0.,  0.,  2., 14.,  5.,
       10., 12.,  0.,  0.,  0.,  0.,  6., 13., 10.,  0.,  0.,  0.])
>>> digits.target[0]    
0      

另外, 透過 fetch_xxxx() 函數則可以擷取真實資料集 :

>>> for d in m:     
    if d.startswith('fetch'):     
        print(d)    
        
fetch_20newsgroups
fetch_20newsgroups_vectorized
fetch_california_housing
fetch_covtype
fetch_kddcup99
fetch_lfw_pairs
fetch_lfw_people
fetch_mldata
fetch_olivetti_faces
fetch_openml
fetch_rcv1
fetch_species_distributions


4. 檢視 sklearn 前處理函數 :   

Scikit-learn 在 preprocessing 模組中提供了豐富的資料前處理函數, 可用 dir() 檢視 : 

>>> from sklearn import preprocessing         
>>> dir(preprocessing)    
['Binarizer', 'CategoricalEncoder', 'FunctionTransformer', 'Imputer', 'KBinsDiscretizer', 'KernelCenterer', 'LabelBinarizer', 'LabelEncoder', 'MaxAbsScaler', 'MinMaxScaler', 'MultiLabelBinarizer', 'Normalizer', 'OneHotEncoder', 'OrdinalEncoder', 'PolynomialFeatures', 'PowerTransformer', 'QuantileTransformer', 'RobustScaler', 'StandardScaler', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_discretization', '_encoders', '_function_transformer', 'add_dummy_feature', 'base', 'binarize', 'data', 'imputation', 'label', 'label_binarize', 'maxabs_scale', 'minmax_scale', 'normalize', 'power_transform', 'quantile_transform', 'robust_scale', 'scale']

可用求值函式 eval() 來取得 preprocessing 類別的成員, 只顯示一般成員, 例如 :

>>> members=dir(preprocessing)
>>> for mbr in members:                      # 走訪成員
    obj=eval('preprocessing.' + mbr)      # 用 eval() 求值取得成員之參考
    if not mbr.startswith('_'):                   # 走訪所有不是 "_" 開頭的成員
        print(mbr, type(obj))
        
Binarizer <class 'type'>
CategoricalEncoder <class 'type'>
FunctionTransformer <class 'type'>
Imputer <class 'type'>
KBinsDiscretizer <class 'type'>
KernelCenterer <class 'type'>
LabelBinarizer <class 'type'>
LabelEncoder <class 'type'>
MaxAbsScaler <class 'type'>
MinMaxScaler <class 'type'>
MultiLabelBinarizer <class 'type'>
Normalizer <class 'type'>
OneHotEncoder <class 'type'>
OrdinalEncoder <class 'type'>
PolynomialFeatures <class 'type'>
PowerTransformer <class 'type'>
QuantileTransformer <class 'type'>
RobustScaler <class 'type'>
StandardScaler <class 'type'>
add_dummy_feature <class 'function'>
base <class 'module'>
binarize <class 'function'>
data <class 'module'>
imputation <class 'module'>
label <class 'module'>
label_binarize <class 'function'>
maxabs_scale <class 'function'>
minmax_scale <class 'function'>
normalize <class 'function'>
power_transform <class 'function'>
quantile_transform <class 'function'>
robust_scale <class 'function'>
scale <class 'function'>

其中 class 為 'type' 者為類別, 'module' 為模組; function 為函式. 

沒有留言 :