scikit-learn介紹

老司機的詩和遠方發表於2020-04-06

在機器學習和資料探勘的應用中,scikit-learn是一個功能強大的python包。在資料量不是過大的情況下,可以解決大部分問題。學習使用scikit-learn的過程中,我自己也在補充著機器學習和資料探勘的知識。這裡根據自己學習sklearn的經驗,我做一個總結的筆記。另外,我也想把這篇筆記一直更新下去。

1 scikit-learn基礎介紹

1.1 估計器(Estimator)

估計器,很多時候可以直接理解成分類器,主要包含兩個函式:

  • fit():訓練演算法,設定內部引數。接收訓練集和類別兩個引數。
  • predict():預測測試集類別,引數為測試集。
    大多數scikit-learn估計器接收和輸出的資料格式均為numpy陣列或類似格式。

1.2 轉換器(Transformer)

轉換器用於資料預處理和資料轉換,主要是三個方法:

  • fit():訓練演算法,設定內部引數。
  • transform():資料轉換。
  • fit_transform():合併fit和transform兩個方法。

1.3 流水線(Pipeline)

sklearn.pipeline

流水線的功能:

  • 跟蹤記錄各步驟的操作(以方便地重現實驗結果)
  • 對各步驟進行一個封裝
  • 確保程式碼的複雜程度不至於超出掌控範圍

基本使用方法

流水線的輸入為一連串的資料探勘步驟,其中最後一步必須是估計器,前幾步是轉換器。輸入的資料集經過轉換器的處理後,輸出的結果作為下一步的輸入。最後,用位於流水線最後一步的估計器對資料進行分類。
每一步都用元組( ‘名稱’,步驟)來表示。現在來建立流水線。

scaling_pipeline = Pipeline([
  ('scale', MinMaxScaler()),
  ('predict', KNeighborsClassifier())
])

1.4 預處理

主要在sklearn.preprcessing包下。

規範化:

  • MinMaxScaler :最大最小值規範化
  • Normalizer :使每條資料各特徵值的和為1
  • StandardScaler :為使各特徵的均值為0,方差為1

編碼:

  • LabelEncoder :把字串型別的資料轉化為整型
  • OneHotEncoder :特徵用一個二進位制數字來表示
  • Binarizer :為將數值型特徵的二值化
  • MultiLabelBinarizer:多標籤二值化

1.5 特徵

1.5.1 特徵抽取

包:sklearn.feature_extraction
特徵抽取是資料探勘任務最為重要的一個環節,一般而言,它對最終結果的影響要高過資料探勘演算法本身。只有先把現實用特徵表示出來,才能藉助資料探勘的力量找到問題的答案。特徵選擇的另一個優點在於:降低真實世界的複雜度,模型比現實更容易操縱。
一般最常使用的特徵抽取技術都是高度針對具體領域的,對於特定的領域,如影像處理,在過去一段時間已經開發了各種特徵抽取的技術,但這些技術在其他領域的應用卻非常有限。

  • DictVectorizer: 將dict型別的list資料,轉換成numpy array
  • FeatureHasher : 特徵雜湊,相當於一種降維技巧
  • image:影像相關的特徵抽取
  • text: 文字相關的特徵抽取
  • text.CountVectorizer:將文字轉換為每個詞出現的個數的向量
  • text.TfidfVectorizer:將文字轉換為tfidf值的向量
  • text.HashingVectorizer:文字的特徵雜湊

示例


data.png


CountVectorize只數出現個數


count.png

hash.png


TfidfVectorizer:個數+歸一化(不包括idf)


tfidf(without idf).png

1.5.2 特徵選擇

包:sklearn.feature_selection
特徵選擇的原因如下:
(1)降低複雜度
(2)降低噪音
(3)增加模型可讀性

  • VarianceThreshold: 刪除特徵值的方差達不到最低標準的特徵
  • SelectKBest: 返回k個最佳特徵
  • SelectPercentile: 返回表現最佳的前r%個特徵

單個特徵和某一類別之間相關性的計算方法有很多。最常用的有卡方檢驗(χ2)。其他方法還有互資訊和資訊熵。

  • chi2: 卡方檢驗(χ2)

1.6 降維

包:sklearn.decomposition

  • 主成分分析演算法(Principal Component Analysis, PCA)的目的是找到能用較少資訊描述資料集的特徵組合。它意在發現彼此之間沒有相關性、能夠描述資料集的特徵,確切說這些特徵的方差跟整體方差沒有多大差距,這樣的特徵也被稱為主成分。這也就意味著,藉助這種方法,就能通過更少的特徵捕獲到資料集的大部分資訊。

1.7 組合

包:sklearn.ensemble
組合技術即通過聚集多個分類器的預測來提高分類準確率。
常用的組合分類器方法:
(1)通過處理訓練資料集。即通過某種抽樣分佈,對原始資料進行再抽樣,得到多個訓練集。常用的方法有裝袋(bagging)和提升(boosting)。
(2)通過處理輸入特徵。即通過選擇輸入特徵的子集形成每個訓練集。適用於有大量冗餘特徵的資料集。隨機森林(Random forest)就是一種處理輸入特徵的組合方法。
(3)通過處理類標號。適用於多分類的情況,將類標號隨機劃分成兩個不相交的子集,再把問題變為二分類問題,重複構建多次模型,進行分類投票。

  • BaggingClassifier: Bagging分類器組合
  • BaggingRegressor: Bagging迴歸器組合
  • AdaBoostClassifier: AdaBoost分類器組合
  • AdaBoostRegressor: AdaBoost迴歸器組合
  • GradientBoostingClassifier:GradientBoosting分類器組合
  • GradientBoostingRegressor: GradientBoosting迴歸器組合
  • ExtraTreeClassifier:ExtraTree分類器組合
  • ExtraTreeRegressor: ExtraTree迴歸器組合
  • RandomTreeClassifier:隨機森林分類器組合
  • RandomTreeRegressor: 隨機森林迴歸器組合

使用舉例

AdaBoostClassifier(DecisionTreeClassifier(max_depth=1),
algorithm="SAMME",
n_estimators=200)

解釋
裝袋(bagging)
:根據均勻概率分佈從資料集中重複抽樣(有放回),每個自助樣本集和原資料集一樣大,每個自助樣本集含有原資料集大約63%的資料。訓練k個分類器,測試樣本被指派到得票最高的類。
提升(boosting):通過給樣本設定不同的權值,每輪迭代調整權值。不同的提升演算法之間的差別,一般是(1)如何更新樣本的權值,(2)如何組合每個分類器的預測。其中Adaboost中,樣本權值是增加那些被錯誤分類的樣本的權值,分類器C_i的重要性依賴於它的錯誤率。
Boosting主要關注降低偏差,因此Boosting能基於泛化效能相當弱的學習器構建出很強的整合;Bagging主要關注降低方差,因此它在不剪枝的決策樹、神經網路等學習器上效用更為明顯。偏差指的是演算法的期望預測與真實預測之間的偏差程度,反應了模型本身的擬合能力;方差度量了同等大小的訓練集的變動導致學習效能的變化,刻畫了資料擾動所導致的影響。

1.8 模型評估(度量)

包:sklearn.metrics
sklearn.metrics包含評分方法、效能度量、成對度量和距離計算。
分類結果度量
引數大多是y_true和y_pred。

  • accuracy_score:分類準確度
  • condusion_matrix :分類混淆矩陣
  • classification_report:分類報告
  • precision_recall_fscore_support:計算精確度、召回率、f、支援率
  • jaccard_similarity_score:計算jcaard相似度
  • hamming_loss:計算漢明損失
  • zero_one_loss:0-1損失
  • hinge_loss:計算hinge損失
  • log_loss:計算log損失

其中,F1是以每個類別為基礎進行定義的,包括兩個概念:準確率(precision)和召回率(recall)。準確率是指預測結果屬於某一類的個體,實際屬於該類的比例。召回率是被正確預測為某類的個體,與資料集中該類個體總數的比例。F1是準確率和召回率的調和平均數。

迴歸結果度量

  • explained_varicance_score:可解釋方差的迴歸評分函式
  • mean_absolute_error:平均絕對誤差
  • mean_squared_error:平均平方誤差

多標籤的度量

  • coverage_error:涵蓋誤差
  • label_ranking_average_precision_score:計算基於排名的平均誤差Label ranking average precision (LRAP)

聚類的度量

  • adjusted_mutual_info_score:調整的互資訊評分
  • silhouette_score:所有樣本的輪廓係數的平均值
  • silhouette_sample:所有樣本的輪廓係數

1.9 交叉驗證

包:sklearn.cross_validation

  • KFold:K-Fold交叉驗證迭代器。接收元素個數、fold數、是否清洗
  • LeaveOneOut:LeaveOneOut交叉驗證迭代器
  • LeavePOut:LeavePOut交叉驗證迭代器
  • LeaveOneLableOut:LeaveOneLableOut交叉驗證迭代器
  • LeavePLabelOut:LeavePLabelOut交叉驗證迭代器

LeaveOneOut(n) 相當於 KFold(n, n_folds=n) 相當於LeavePOut(n, p=1)。
LeaveP和LeaveOne差別在於leave的個數,也就是測試集的尺寸。LeavePLabel和LeaveOneLabel差別在於leave的Label的種類的個數。
LeavePLabel這種設計是針對可能存在第三方的Label,比如我們的資料是一些季度的資料。那麼很自然的一個想法就是把1,2,3個季度的資料當做訓練集,第4個季度的資料當做測試集。這個時候只要輸入每個樣本對應的季度Label,就可以實現這樣的功能。
以下是實驗程式碼,儘量自己多實驗去理解。

#coding=utf-8
import numpy as np
import sklearnfrom sklearn
import cross_validation
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8],[9, 10]])
y = np.array([1, 2, 1, 2, 3])
def show_cross_val(method):    
  if method == "lolo":        
    labels = np.array(["summer", "winter", "summer", "winter", "spring"])        
    cv = cross_validation.LeaveOneLabelOut(labels)          
  elif method == 'lplo':        
    labels = np.array(["summer", "winter", "summer", "winter", "spring"])        
    cv = cross_validation.LeavePLabelOut(labels,p=2)    
  elif method == 'loo':        
    cv = cross_validation.LeaveOneOut(n=len(y))    
  elif method == 'lpo':        
    cv = cross_validation.LeavePOut(n=len(y),p=3)    
  for train_index, test_index in cv:        
    print("TRAIN:", train_index, "TEST:", test_index)        
    X_train, X_test = X[train_index], X[test_index]        
    y_train, y_test = y[train_index], y[test_index]        
    print "X_train: ",X_train        
    print "y_train: ", y_train        
    print "X_test: ",X_test        
    print "y_test: ",y_test
if __name__ == '__main__':    
  show_cross_val("lpo")

常用方法

  • train_test_split:分離訓練集和測試集(不是K-Fold)
  • cross_val_score:交叉驗證評分,可以指認cv為上面的類的例項
  • cross_val_predict:交叉驗證的預測。

1.10 網格搜尋

包:sklearn.grid_search
網格搜尋最佳引數

  • GridSearchCV:搜尋指定引數網格中的最佳引數
  • ParameterGrid:引數網格
  • ParameterSampler:用給定分佈生成引數的生成器
  • RandomizedSearchCV:超參的隨機搜尋
    通過best_estimator_.get_params()方法,獲取最佳引數。

1.11 多分類、多標籤分類

包:sklearn.multiclass

  • OneVsRestClassifier:1-rest多分類(多標籤)策略
  • OneVsOneClassifier:1-1多分類策略
  • OutputCodeClassifier:1個類用一個二進位制碼錶示
    示例程式碼
    #coding=utf-8
    from sklearn import metrics
    from sklearn import cross_validation
    from sklearn.svm import SVC
    from sklearn.multiclass import OneVsRestClassifier
    from sklearn.preprocessing import MultiLabelBinarizer
    import numpy as np
    from numpy import random
    X=np.arange(15).reshape(5,3)
    y=np.arange(5)
    Y_1 = np.arange(5)
    random.shuffle(Y_1)
    Y_2 = np.arange(5)
    random.shuffle(Y_2)
    Y = np.c_[Y_1,Y_2]
    def multiclassSVM():
      X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2,random_state=0)
      model = OneVsRestClassifier(SVC())
      model.fit(X_train, y_train)
      predicted = model.predict(X_test)
      print predicted
    def multilabelSVM():
      Y_enc = MultiLabelBinarizer().fit_transform(Y)
      X_train, X_test, Y_train, Y_test = cross_validation.train_test_split(X, Y_enc, test_size=0.2, random_state=0)
      model = OneVsRestClassifier(SVC())
      model.fit(X_train, Y_train)
      predicted = model.predict(X_test)
      print predicted
    if __name__ == '__main__':
      multiclassSVM()
      # multilabelSVM()
    上面的程式碼測試了svm在OneVsRestClassifier的包裝下,分別處理多分類和多標籤的情況。特別注意,在多標籤的情況下,輸入必須是二值化的。所以需要MultiLabelBinarizer()先處理。

2 具體模型

2.1 樸素貝葉斯(Naive Bayes)

包:sklearn.cross_validation


樸素貝葉斯.png


樸素貝葉斯的特點是分類速度快,分類效果不一定是最好的。

  • GasussianNB:高斯分佈的樸素貝葉斯
  • MultinomialNB:多項式分佈的樸素貝葉斯
  • BernoulliNB:伯努利分佈的樸素貝葉斯

所謂使用什麼分佈的樸素貝葉斯,就是假設P(x_i|y)是符合哪一種分佈,比如可以假設其服從高斯分佈,然後用最大似然法估計高斯分佈的引數。


高斯分佈.png

多項式分佈.png

伯努利分佈.png

3 scikit-learn擴充套件

3.0 概覽

具體的擴充套件,通常要繼承sklearn.base包下的類。

  • BaseEstimator: 估計器的基類
  • ClassifierMixin :分類器的混合類
  • ClusterMixin:聚類器的混合類
  • RegressorMixin :迴歸器的混合類
  • TransformerMixin :轉換器的混合類

關於什麼是Mixin(混合類),具體可以看這個知乎連結。簡單地理解,就是帶有實現方法的介面,可以將其看做是組合模式的一種實現。舉個例子,比如說常用的TfidfTransformer,繼承了BaseEstimator, TransformerMixin,因此它的基本功能就是單一職責的估計器和轉換器的組合。

3.1 建立自己的轉換器

在特徵抽取的時候,經常會發現自己的一些資料預處理的方法,sklearn裡可能沒有實現,但若直接在資料上改,又容易將程式碼弄得混亂,難以重現實驗。這個時候最好自己建立一個轉換器,在後面將這個轉換器放到pipeline裡,統一管理。
例如《Python資料探勘入門與實戰》書中的例子,我們想接收一個numpy陣列,根據其均值將其離散化,任何高於均值的特徵值替換為1,小於或等於均值的替換為0。
程式碼實現:

from sklearn.base import TransformerMixin
from sklearn.utils import as_float_array

class MeanDiscrete(TransformerMixin):

  #計算出資料集的均值,用內部變數儲存該值。  
  def fit(self, X, y=None):
        X = as_float_array(X)
        self.mean = np.mean(X, axis=0)
        #返回self,確保在轉換器中能夠進行鏈式呼叫(例如呼叫transformer.fit(X).transform(X))
        return self

    def transform(self, X):
        X = as_float_array(X)
        assert X.shape[1] == self.mean.shape[0]
        return X > self.mean


作者:Cer_ml
連結:http://www.jianshu.com/p/516f009c0875
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。