天天看點

使用Sklearn進行資料挖掘

1 使用sklearn進行資料挖掘

1.1 資料挖掘的步驟

資料挖掘通常包括資料采集,資料分析,特征工程,訓練模型,模型評估等步驟。使用sklearn工具可以友善地進行特征工程和模型訓練工作,在《使用sklearn做單機特征工程》中,我們最後留下了一些疑問:特征處理類都有三個方法fit、transform和fit_transform,fit方法居然和模型訓練方法fit同名(不光同名,參數清單都一樣),這難道都是巧合?

<a href="http://s4.51cto.com/oss/201710/31/a310f4d8e8a90871dd6771e5cff9fd18.jpg-wh_651x-s_3719181887.jpg" target="_blank"></a>

顯然,這不是巧合,這正是sklearn的設計風格。我們能夠更加優雅地使用sklearn進行特征工程和模型訓練工作。此時,不妨從一個基本的資料挖掘場景入手:

<a href="http://s5.51cto.com/oss/201710/31/35f968c1528620715ef7b08641d1d6b3.png" target="_blank"></a>

我們使用sklearn進行虛線框内的工作(sklearn也可以進行文本特征提取)。通過分析sklearn源碼,我們可以看到除訓練,預測和評估以外,處理其他工作的類都實作了3個方法:fit、transform和fit_transform。從命名中可以看到,fit_transform方法是先調用fit然後調用transform,我們隻需要關注fit方法和transform方法即可。

transform方法主要用來對特征進行轉換。從可利用資訊的角度來說,轉換分為無資訊轉換和有資訊轉換。無資訊轉換是指不利用任何其他資訊進行轉換,比如指數、對數函數轉換等。有資訊轉換從是否利用目标值向量又可分為無監督轉換和有監督轉換。無監督轉換指隻利用特征的統計資訊的轉換,統計資訊包括均值、标準差、邊界等等,比如标準化、PCA法降維等。有監督轉換指既利用了特征資訊又利用了目标值資訊的轉換,比如通過模型選擇特征、LDA法降維等。通過總結常用的轉換類,我們得到下表:

<a href="http://s4.51cto.com/oss/201710/31/0a309bf30e2f34b09a4a13b0b5cbd26a.png" target="_blank"></a>

不難看到,隻有有資訊的轉換類的fit方法才實際有用,顯然fit方法的主要工作是擷取特征資訊和目标值資訊,在這點上,fit方法和模型訓練時的fit方法就能夠聯系在一起了:都是通過分析特征和目标值,提取有價值的資訊,對于轉換類來說是某些統計量,對于模型來說可能是特征的權值系數等。另外,隻有有監督的轉換類的fit和transform方法才需要特征和目标值兩個參數。fit方法無用不代表其沒實作,而是除合法性校驗以外,其并沒有對特征和目标值進行任何處理,Normalizer的fit方法實作如下:

def fit(self, X, y=None): 

"""Do nothing and return the estimator unchanged 

This method is just there to implement the usual API and hence 

work in pipelines. 

""" 

X = check_array(X, accept_sparse='csr') 

return self 

基于這些特征處理工作都有共同的方法,那麼試想可不可以将他們組合在一起?在本文假設的場景中,我們可以看到這些工作的組合形式有兩種:流水線式和并行式。基于流水線組合的工作需要依次進行,前一個工作的輸出是後一個工作的輸入;基于并行式的工作可以同時進行,其使用同樣的輸入,所有工作完成後将各自的輸出合并之後輸出。sklearn提供了包pipeline來完成流水線式和并行式的工作。

1.2 資料初貌

在此,我們仍然使用IRIS資料集來進行說明。為了适應提出的場景,對原資料集需要稍微加工:

from numpy import hstack, vstack, array, median, nan 

from numpy.random import choice 

from sklearn.datasets import load_iris  

#特征矩陣加工 

#使用vstack增加一行含缺失值的樣本(nan, nan, nan, nan) 

#使用hstack增加一清單示花的顔色(0-白、1-黃、2-紅),花的顔色是随機的,意味着顔色并不影響花的分類 

iris.data = hstack((choice([0, 1, 2], size=iris.data.shape[0]+1).reshape(-1,1), vstack((iris.data, array([nan, nan, nan, nan]).reshape(1,-1))))) 

#目标值向量加工 

#增加一個目标值,對應含缺失值的樣本,值為衆數 

iris.target = hstack((iris.target, array([median(iris.target)]))) 

1.3 關鍵技術

并行處理,流水線處理,自動化調參,持久化是使用sklearn優雅地進行資料挖掘的核心。并行處理和流水線處理将多個特征處理工作,甚至包括模型訓練工作組合成一個工作(從代碼的角度來說,即将多個對象組合成了一個對象)。在組合的前提下,自動化調參技術幫我們省去了人工調參的反鎖。訓練好的模型是貯存在記憶體中的資料,持久化能夠将這些資料儲存在檔案系統中,之後使用時無需再進行訓練,直接從檔案系統中加載即可。

2 并行處理

并行處理使得多個特征處理工作能夠并行地進行。根據對特征矩陣的讀取方式不同,可分為整體并行處理和部分并行處理。整體并行處理,即并行處理的每個工作的輸入都是特征矩陣的整體;部分并行處理,即可定義每個工作需要輸入的特征矩陣的列。

2.1 整體并行處理

pipeline包提供了FeatureUnion類來進行整體并行處理:

from numpy import log1p 

from sklearn.preprocessing import FunctionTransformer 

from sklearn.preprocessing import Binarizer 

from sklearn.pipeline import FeatureUnion  

 #建立将整體特征矩陣進行對數函數轉換的對象 

step2_1 = ('ToLog', FunctionTransformer(log1p)) 

#建立将整體特征矩陣進行二值化類的對象 

step2_2 = ('ToBinary', Binarizer()) 

#建立整體并行處理對象 

#該對象也有fit和transform方法,fit和transform方法均是并行地調用需要并行處理的對象的fit和transform方法 

#參數transformer_list為需要并行處理的對象清單,該清單為二進制組清單,第一進制為對象的名稱,第二進制為對象 

 step2 = ('FeatureUnion', FeatureUnion(transformer_list=[step2_1, step2_2, step2_3])) 

2.2 部分并行處理

整體并行處理有其缺陷,在一些場景下,我們隻需要對特征矩陣的某些列進行轉換,而不是所有列。pipeline并沒有提供相應的類(僅OneHotEncoder類實作了該功能),需要我們在FeatureUnion的基礎上進行優化:

View Code

在本文提出的場景中,我們對特征矩陣的第1列(花的顔色)進行定性特征編碼,對第2、3、4列進行對數函數轉換,對第5列進行定量特征二值化處理。使用FeatureUnionExt類進行部分并行處理的代碼如下:

from sklearn.preprocessing import OneHotEncoder 

from sklearn.preprocessing import Binarizer  

#建立将部分特征矩陣進行定性特征編碼的對象 

step2_1 = ('OneHotEncoder', OneHotEncoder(sparse=False)) 

#建立将部分特征矩陣進行對數函數轉換的對象 

step2_2 = ('ToLog', FunctionTransformer(log1p)) 

#建立将部分特征矩陣進行二值化類的對象 

step2_3 = ('ToBinary', Binarizer()) 

#建立部分并行處理對象 

#參數idx_list為相應的需要讀取的特征矩陣的列 

step2 = ('FeatureUnionExt', FeatureUnionExt(transformer_list=[step2_1, step2_2, step2_3], idx_list=[[0], [1, 2, 3], [4]])) 

3 流水線處理

pipeline包提供了Pipeline類來進行流水線處理。流水線上除最後一個工作以外,其他都要執行fit_transform方法,且上一個工作輸出作為下一個工作的輸入。最後一個工作必須實作fit方法,輸入為上一個工作的輸出;但是不限定一定有transform方法,因為流水線的最後一個工作可能是訓練!

根據本文提出的場景,結合并行處理,建構完整的流水線的代碼如下:

from sklearn.preprocessing import Imputer 

from sklearn.preprocessing import MinMaxScaler 

from sklearn.feature_selection import SelectKBest 

from sklearn.feature_selection import chi2 

from sklearn.decomposition import PCA 

from sklearn.linear_model import LogisticRegression 

from sklearn.pipeline import Pipeline 

#建立計算缺失值的對象 

step1 = ('Imputer', Imputer()) 

#建立部分并行處理對象,傳回值為每個并行工作的輸出的合并 

#建立無量綱化對象 

step3 = ('MinMaxScaler', MinMaxScaler()) 

#建立卡方校驗選擇特征的對象 

step4 = ('SelectKBest', SelectKBest(chi2, k=3)) 

#建立PCA降維的對象 

step5 = ('PCA', PCA(n_components=2)) 

#建立邏輯回歸的對象,其為待訓練的模型作為流水線的最後一步 

step6 = ('LogisticRegression', LogisticRegression(penalty='l2')) 

#建立流水線處理對象 

#參數steps為需要流水線處理的對象清單,該清單為二進制組清單,第一進制為對象的名稱,第二進制為對象 

pipeline = Pipeline(steps=[step1, step2, step3, step4, step5, step6]) 

4 自動化調參

網格搜尋為自動化調參的常見技術之一,grid_search包提供了自動化調參的工具,包括GridSearchCV類。對組合好的對象進行訓練以及調參的代碼如下:

from sklearn.grid_search import GridSearchCV 

#建立網格搜尋對象 

#第一參數為待訓練的模型 

#param_grid為待調參數組成的網格,字典格式,鍵為參數名稱(格式“對象名稱__子對象名稱__參數名稱”),值為可取的參數值清單 

grid_search = GridSearchCV(pipeline, param_grid={'FeatureUnionExt__ToBinary__threshold':[1.0, 2.0, 3.0, 4.0], 'LogisticRegression__C':[0.1, 0.2, 0.4, 0.8]}) 

#訓練以及調參 

grid_search.fit(iris.data, iris.target) 

5 持久化

externals.joblib包提供了dump和load方法來持久化和加載記憶體資料:

#持久化資料 

#第一個參數為記憶體中的對象 

#第二個參數為儲存在檔案系統中的名稱 

#第三個參數為壓縮級别,0為不壓縮,3為合适的壓縮級别 

dump(grid_search, 'grid_search.dmp', compress=3) 

#從檔案系統中加載資料到記憶體中 

grid_search = load('grid_search.dmp') 

6 回顧

<a href="http://s5.51cto.com/oss/201710/31/2226878f2ac2b26cb7204183c5d58f3c.png" target="_blank"></a>

注意:組合和持久化都會涉及pickle技術,在sklearn的技術文檔中有說明,将lambda定義的函數作為FunctionTransformer的自定義轉換函數将不能pickle化。

7 總結

2015年我設計了一個基于sklearn的自動化特征工程的工具,其以Mysql資料庫作為原始資料源,提供了“靈活的”特征提取、特征處理的配置方法,同時重新封裝了資料、特征和模型,以友善排程系統識别。說靈活,其實也隻是通過配置檔案的方式定義每個特征的提取和處理的sql語句。但是純粹使用sql語句來進行特征處理是很勉強的,除去特征提取以外,我又造了一回輪子,原來sklearn提供了這麼優秀的特征處理、工作組合等功能。是以,我在這個部落格中先不提任何算法和模型,先從資料挖掘工作的第一步開始,使用基于Python的各個工具把大部分步驟都走了一遍(抱歉,我暫時忽略了特征提取),希望這樣的梳理能夠少讓初學者走彎路吧。 

原文釋出時間為:2017-10-31 

本文作者:佚名

本文來自雲栖社群合作夥伴“51CTO”,了解相關資訊可以關注。