1. 程式人生 > >機器學習三人行(系列三)---End-to-End機器學習建模

機器學習三人行(系列三)---End-to-End機器學習建模

原文連結:閱讀原文 歡迎大家關注微信公眾號“智慧演算法”,我們一起學習,共同進步。 系列二我們詳細介紹了資料下載,資料透析以及資料的不同分組方式,詳情請戳我!。但是在真正進行訓練之前,我們還需要對資料進行一個預處理。因為有些資料有一些缺失,以及怎麼處理分類變數,歸一化之類的操作,這樣演算法才能夠表現出更好的效能。通常預處理有以下幾個步驟:缺失值和離群值處理(看情況),特徵表徵(使模型理解資料),歸一化,那麼我們接著系列二一起繼續學習。 一、資料清洗 再次觀察資料集,通過housing.shape,可以檢視資料集大小(16512, 13),資料集的特徵如下: 發現totals_rooms和bedrooms_per_room存在資料缺失的情況,由於一些機器學習演算法無法計算缺失資料,因此需要對缺失值適當的處理工作。
1.1 缺失值處理 常用處理方法:對丟棄包含缺失值的行或列、對缺失值進行填充。我們來檢視缺失的佔比情況: 發現只有少部分缺失,因此丟棄行或列是不合適的,不然會損失有用的資訊,因此考慮對缺失值進行填充,而填充又包含填充中位數,眾數,均值,常量值(如-1),多值插補或通過建模對缺失值進行預測等方法。考慮本例只有少部分缺失值,因此使用中位數填充,方法: from sklearn.preprocessing import Imputer imputer = Imputer(strategy="median") imputer.fit(housing_num) 考慮中位數填充缺失值只能對數值處理,對object的
ocean_proximity是無效的。因此將數值型相關特徵從資料集中抽出來,housing_num = housing.drop('ocean_proximity', axis=1)。 接下來可以對housing_num做缺失值處理了,X = imputer.transform(housing_num) ,X就是處理後的結果生成一個新的dataframe,如下: housing_tr = pd.DataFrame(X, columns=housing_num.columns, index = list(housing.index.values)) 檢視生成housing_tr的處理後結果。
2.2 分類變數 housing資料集中唯一的分類特徵ocean_proximity,將ocean_proximity特徵拿出來處理,housing_cat = housing['ocean_proximity'],檢視類別的構成如下: 由於機器學習演算法是沒有辦法理解字元的分類變數的,因此需要將字元的分類特徵轉換成數值型分類特徵,我們採用pandas中factorize()來完成轉換 雖然完成數值型分類特徵的轉換,但是這樣處理會引入一個問題,轉換的分類變數變成有序和可比較了,即,轉換後的0,1,2,3,4,是不是能說0,1變數的距離和1,2的距離是一樣的。這樣明顯和原來的分類的特性是不符合的,要消除這個問題,需要使用OneHotEncoder來處理。 其實上面的從factorize到One-Hot encode可以使用sklearn.preprocessing.LabelBinarizer一步完成 因此類似One-Hot也會存在一個問題,如果分類變數的類別過多時,會導致出現維度災難。 2.3 特徵歸一化 由於特徵不同的分佈範圍,對一些演算法尋優速度和收斂有影響,比如SVM,因此再進入模型前需要對特徵進行歸一化,常用的歸一化有:Min-Max Scaling和Z-Score Standardization兩種。分別對應sklearn中MinMaxScaler和StandardScaler方法。而且StandardScaler更多是應用在特徵存在偏態分佈的情況下,根據系列二中特徵的分佈情況,這裡採用StandardScaler進行特徵歸一化。 二、pipeline流水線 通過上面的處理,我們已經對資料進行了基本的資料清洗工作,我們可以拿上面處理好的資料直接進行建模了,但是這裡會面臨兩個問題:一個是我們是把數值型特徵和分型別特徵分別處理的,因此需要合併,二是後面對於驗證集的預測前,驗證資料集需要按照的處理流程重新跑一遍,才能進行預測,就需要將訓練集的一些特殊的處理過程儲存,應用到驗證集和測試集的處理上。 想想如果需要對訓練集的處理方法修改的話,將是更加麻煩的事情,這裡就需要引入了sklearn中一個強大的工具,pipeline,把我們的處理過程流水線化,對驗證集和測試集上呼叫fit、transform就可以完成處理,然後扔到模型中去預測,而且配合FeatureUnion還可以完成並行處理。過程大致如下: 2.1 自定義方法 sklearn的pipeline要完成流程化處理,呼叫的函式必須包含三種方法:fit(),transform(),和fit_transform。而且是隻要包含這三種方法都可以放到pipeline中去,也就是說,我們可以自己寫方法,只需要定義好這三個方法就可以了,最後一個fit_transform方法,只需要通過繼承TransformerMixin方法就可以獲得,因此只需要我們定義fit和transform方法就可以了,可以把系列二中特徵融合自己定義一個pipeline方法: attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False) housing_extra_attribs = attr_adder.transform(housing.values) 通過上面呼叫測試方法是否可用。 2.2 sklearn可用方法 sklearn本身包含了豐富的預處理和特徵處理的方法,比如在預處理中使用到的StandardScaler,Imputer等,下面列舉了一些sklearn常用的處理方法,更多內容可以檢視sklearn的官網: 2.3 本文使用方法 通過上面的方法可以完成將前面對數值型特徵的處理寫成一個pipeline: 由於我們的處理分成的數值型特徵處理和分類特徵的處理兩部分,如果寫成兩個pipeline來分別處理的話,最後需要將結果合併,還是太麻煩了,因此我們還需要一個對選擇資料集的pipeline處理方法: 有了DataframeSelector方法,我們通過FeatureUnion的並行化處理來寫一個完整的pipeline處理流程如下: 通過呼叫:housing_prepared = full_pipeline.fit_transform(housing)完成全部的處理過程。 三、建立模型 3.1 基準模型 通過上面full_pipeline,資料的預處理已經完成,接下來利用處理好的資料建立模型,我們選擇簡單的線性迴歸,作為基準模型,後續在此基礎上不斷優化模型效果。 from sklearn.linear_model import LinearRegression lin_reg = LinearRegression() lin_reg.fit(housing_prepared, housing_labels) 我們嘗試取原資料前五條資料來預測,觀測效果 some_data = housing.iloc[:5] some_labels = housing_labels.iloc[:5] some_data_prepared = full_pipeline.transform(some_data) print("Predictions:", lin_reg.predict(some_data_prepared)) 預測結果: Predictions: [ 210644.60459286 317768.80697211 210956.43331178 59218.98886849 189747.55849879] 而原資料的實際值為: Actual: [286600.0, 340600.0, 196900.0, 46300.0, 254500.0] 對於迴歸問題,常用的評估指標有均方根誤差(RMSE),平均絕對差值(MAE),RMSE在可以使用sklearn的mean_squared_error計算,MAE對應mean_absolute_error。對測試的預測值計算評估指標結果如下: 在此基礎上可以嘗試各種不同的模型,通過比較評估指標,獲取最合適的模型,作為最終的建模模型,當然上面的評估只是作為模型預測的測試,實際中我們需要將資料集劃分出訓練集和驗證集,通過交叉驗證的方法來評估。 3.2交叉驗證 交叉驗證,可以使用sklearn的cross_val_score來完成,計算之前先寫一個結果的展示函式,方便檢視結果: def display_scores(scores): print("Scores:", scores) print("Mean:", scores.mean()) print("Standard deviation:", scores.std()) 接下來我們通過建立隨機森林來,通過交叉驗證來評估模型效果; 構建模型: 效果評估: 通過10折交叉驗證,得到最終的平均RMSE值:52564.19。通過類似方法可以比較不同的模型的預測效果。 四、引數調整 當我們使用機器學習演算法時,會發現幾乎所有的演算法都包括一些超引數,這些引數和常規引數不同,它們不是模型的一部分,不會在模型擬閤中被自動調整。它們是在另外的步驟中被調整的。一些超引數的例子,包括在嶺迴歸和lasso迴歸中的正則項lambda、支援向量機中的C項、基於樹的演算法中樹的數量(如,隨機森林、梯度提升機)。 常用的超引數優化方法有:網格搜尋,隨機搜尋,貝葉斯優化,sklearn已經為我們提供了網格搜尋和隨機搜尋的方法實現,貝葉斯優化也有一些的實現包,而且貝葉斯優化在一些資料探勘競賽kaggle中用的比較多。 4.1. 網格搜尋 網格搜尋是在我們預先設定的引數的不同超引數取值中,組成出最優結果的超引數方法,如對上面的隨機森林演算法尋找最優引數 上面的網格搜尋會對12種n_estimators和max_features的組合建模和6種boostrap的引數組合來尋找最優引數,也就是系統會自動建立18個模型,自動比較出最優的引數,最後通過grid_search.best_params_可以檢視最優的模型引數。 4.2. 隨機搜尋 隨機搜尋的思想和網格搜尋比較相似,只是不再搜尋上界和下界之間的所有值,只是在搜尋範圍中隨機取樣本點。它的理論依據是,如果隨即樣本點集足夠大,那麼也可以找到全域性的最大或最小值,或它們的近似值。通過對搜尋範圍的隨機取樣,隨機搜尋一般會比網格搜尋要快一些。但是和網格搜尋的快速版(非自動版)相似,結果也是沒法保證的。下面通過隨機搜尋來尋找最優引數。 使用隨機搜尋還有一個好處是我們可以設定搜尋迭代的次數來控制對調參的資源分配。 4.3. 貝葉斯優化 貝葉斯優化尋找使全域性達到最值的引數時,使用了和網格搜尋、隨機搜尋完全不同的方法。網格搜尋和隨機搜尋在測試一個新的點時,會忽略前一個點的資訊。而貝葉斯優化充分利用了這個資訊。貝葉斯優化的工作方式是通過對目標函式形狀的學習,找到使結果向全域性最大值提升的引數。它學習目標函式形狀的方法是,根據先驗分佈,假設一個蒐集函式。在每一次使用新的取樣點來測試目標函式時,它使用這個資訊來更新目標函式的先驗分佈。然後,演算法測試由後驗分佈給出的,全域性最值最可能出現的位置的點。關於貝葉斯優化的原理可以在公眾號中回覆"貝葉斯優化",可以獲取到相關論文。 關於該方法的調參在github上已經有人根據論文內容,把演算法實現了,而且在kaggle比賽中得到廣泛使用。它的python包名叫bayes_opt。可以通過pip install bayesian-optimization來安裝。安裝成功後可以使用bayes_opt來進行引數優化,使用例項如下: 通過robf.maximize(n_iter=10)檢視優化過程並獲取最優值,由於bayes_opt只能求最大值,因此rfccv輸出需要轉換成10000/np.sqrt(-val)。 對於貝葉斯優化,一個主要需要注意的地方,是一旦它找到了一個區域性最大值或最小值,它會在這個區域不斷取樣,所以它很容易陷入區域性最值。為了減輕這個問題,貝葉斯優化演算法會在勘探和開採(exploration and exploitation)中找到一個平衡點。勘探(exploration),就是在還未取樣的區域獲取取樣點。開採(exploitation),就是根據後驗分佈,在最可能出現全域性最值的區域進行取樣。 五、模型評估 通過模型的調參,獲取最優引數,利用最優引數建立我們最終的模型。前面我們是在訓練集和驗證集訓練得到最優模型,但是最終決定模型是否可用,是需要通過評估模型在測試集上的預測表現,這是我們的最終一步,通過比較模型在測試集的表現決定模型的效果,正常來說,測試集的表現會比驗證集上的表現稍差,但是差別不會太大,如果模型的預測差別很大的,那麼可能由兩個原因導致:1、出現過擬合現象,2、測試集和驗證集特徵分佈有較大差別。因此需要從這兩個方面進行排查,另外,看到模型在測試集上效果不佳,千萬不要基於測試集來進行調參以達到模型在測試集上的表現,這樣並不能提高模型的泛化能力,而只是測試集又變成了驗證集,再後續新的測試集上還是會出現同樣的問題。 (如需更好的瞭解相關知識,歡迎加入智慧演算法社群,在“智慧演算法”公眾號傳送“社群”,即可加入演算法微信群和QQ群)