【導讀】這是一篇完全手把手進行機器學習項目構建的教程,包含:1. 數據清理和格式化 2. 探索性數據分析 3. 特徵工程和特徵選擇 4. 在性能指標上比較幾種機器學習模型 5. 對最佳模型執行超參數調整 6. 在測試集合中評估最佳模型 7. 解釋模型結果 8. 得出結論。在第一篇文章中,我們對數據進行了清理和結構化,進行了探索性的數據分析,開發了一組用於我們模型的特徵,並建立了一個基準(baseline)來衡量性能。在本文中,我們將討論如何實現和比較Python中的幾種機器學習模型,執行超參數優化,對最佳模型進行優選,並對測試集上的最終模型進行評估。
【乾貨】Python機器學習項目實戰1(附代碼)
作者 | William Koehrsen
編譯 | 專知
用python完成一個完整的機器學習項目:第二部分
——Model Selection, Hyperparameter Tuning, and Evaluation
集合解決問題所需的所有機器學習程序可能是一項艱巨的任務。在本系列文章中,我們將通過使用真實數據集實現機器學習工作流程,以了解各個技術是如何結合在一起的。
此項目的完整代碼在GitHub上,並附上與本文相對應的參考筆記。您可以隨意使用、共享和修改代碼!
第二部分代碼:
https://github.com/WillKoehrsen/machine-learning-project-walkthrough/blob/master/Machine%20Learning%20Project%20Part%202.ipynb
模型評估和選擇(Model Evaluation and Selection)
作為一個提醒,我們正在研究一個有監督的回歸任務(a supervised regression task):利用紐約市建築能源數據(New York City building energy data),我們想開發一個模型,可以預測建築物的能源之星得分(Energy Star Score)。我們關注的重點是預測的準確性和模型的可解釋性。
有大量的機器學習模型可供選擇,這會讓你難以決定從哪裡開始。雖然有些圖表試圖告訴你要使用哪種算法,但我更願意多嘗試幾種算法,並查看哪種算法效果最好!機器學習仍然是一個主要由經驗(實驗)而不是理論結果驅動的領域,事先知道哪種模型最好,幾乎是不可能的。
一般來說,從簡單的可解釋模型(如線性回歸)開始是一個好辦法,如果性能不足,繼而轉向更複雜但通常更準確的模型。下圖顯示了一種版本的準確性與可解釋性之間的權衡:
我們將評估五種不同的模型:
• 線性回歸(Linear Regression)
• K最近鄰回歸(K-Nearest Neighbors Regression)
• 隨機森林回歸(Random Forest Regression)
• 梯度增強回歸(Gradient Boosted Regression)
• 支持向量機回歸(Support Vector Machine Regression)
在這篇文章中,我們將著重於實現這些方法而不是背後的理論。對於想要了解背景知識的人來說,我強烈推薦閱讀「An Introduction to Statistical Learning 「【1】,或者「Hands-On Machine Learning with Scikit-Learn and TensorFlow」【2】。這兩本書都很好地解釋了理論,並展示了如何分別有效地使用R和Python中的方法。
雖然我們在處理數據時丟失了超過50%缺失值的列,但仍有不少觀察結果丟失。 機器學習模型無法處理任何缺失值,因此我們必須把它們填充進去,這是一個稱為Imputing的過程【3】。
首先,我們將讀入所有數據並提醒自己這些數據是什麼樣子的:
import pandas as pd
import numpy as np
# Read in data into dataframes
train_features = pd.read_csv('data/training_features.csv')
test_features = pd.read_csv('data/testing_features.csv')
train_labels = pd.read_csv('data/training_labels.csv')
test_labels = pd.read_csv('data/testing_labels.csv')
Training Feature Size: (6622, 64)
Testing Feature Size: (2839, 64)
Training Labels Size: (6622, 1)
Testing Labels Size: (2839, 1)
顯示NaN的值都代表缺少觀察結果。雖然有很多方法可以填補缺失數據,但我們將使用一種相對簡單的方法,即中值插補法(median imputation)。這將使用該列的中值(the median value)替換列中的所有缺失值。
在下面的代碼中,我們創建了一個Scikit-Learn Imputer對象,並將strategy設置為median。 然後我們在訓練數據上訓練這個對象(使用imputer.fit),並用它來填充訓練和測試數據中的缺失值(使用imputer.transform)。 這意味著測試數據中的缺失值將填入訓練數據的相應中值。
(我們必須這樣做插補(imputation),而不是對所有數據進行訓練,這樣做是為了避免測試數據洩漏問題(test data leakage),測試數據集中的信息會溢出到訓練數據中。)
# Create an imputer object with a median filling strategy
imputer = Imputer(strategy='median')
# Train on the training features
imputer.fit(train_features)
# Transform both training data and testing data
X = imputer.transform(train_features)
X_test = imputer.transform(test_features)
Missing values in training features: 0
Missing values in testing features: 0
現在所有的特徵都具有真實的,有限的值,沒有缺失值。
縮放(Scaling)是指改變特徵範圍的一般過程。這是必要的,因為特徵是以不同單位測量的,因此涵蓋了不同的範圍。比如支持向量機(svm)和考慮到觀測之間的距離度量的K-近鄰的方法,這兩種方法顯著地受到特徵範圍的影響,Scaling使得他們可以學習(learn)。儘管線性回歸和隨機森林等方法實際上並不需要特徵縮放,但在比較多種算法時採取這一步驟仍然是最佳做法。
我們將每個特徵縮放至0-1之間。通過獲取每個特徵值,減去特徵中的最小值並除以最大值減去最小值(範圍)來完成。這種縮放通常稱為歸一化(normalization),或者標準化(standardization)。
雖然這個過程很容易通過人工計算實現,但我們可以在Scikit-Learn中使用MinMaxScaler對象來完成。此方法的代碼與imputation相同,除了使用scaler來代替imputer!再次,我們確保僅使用訓練數據進行訓練,之後再轉換所有數據。
# Create the scaler object with a range of 0-1
scaler = MinMaxScaler(feature_range=(0, 1))
# Fit on the training data
scaler.fit(X)
# Transform both the training and testing data
X = scaler.transform(X)
X_test = scaler.transform(X_test)
現在,每個特徵的最小值為0,最大值為1。缺少值插補(Missing value imputation)和特徵縮放(feature scaling)是幾乎所有機器學習流程所需的兩個步驟,因此很有必要理解它們的工作原理!
在我們花費大量時間對數據進行清理和格式化之後,實際創建,訓練和預測模型相對簡單。我們將在Python中使用Scikit-Learn庫,它有著很好的說明文檔和一致的模型構建語法。 一旦你知道如何在Scikit-Learn中創建一個模型,你就可以快速實現各種算法。
我們通過一個例子來說明如何進行模型的創建,訓練(.fit)和測試(.predict),使用Gradient Boosting Regressor:
from sklearn.ensemble import GradientBoostingRegressor
# Create the model
gradient_boosted = GradientBoostingRegressor()
# Fit the model on the training data
gradient_boosted.fit(X, y)
# Make predictions on the test data
predictions = gradient_boosted.predict(X_test)
# Evaluate the model
mae = np.mean(abs(predictions - y_test))
print('Gradient Boosted Performance on the test set: MAE = %0.4f' % mae)
Gradient Boosted Performance on the test set: MAE = 10.0132
模型的創建,訓練和測試都是一條線!構建其他模型,我們使用相同的語法,只改變算法的名稱。 結果如下:
為了使這些數字正確,用目標的中值計算的樸素baseline是24.5。顯然,機器學習適用於我們的問題,因為相比於baseline有顯著的提高!
梯度增強回歸(MAE = 10.013)略優於隨機森林(MAE = 10.014)。這些結果並不完全公平,因為我們主要使用了超參數的默認值。特別是在支持向量機等模型中,性能高度依賴於這些設置。最終,從這些比較的結果中,我們將選擇梯度增強回歸(gradient boosted regressor)模型來進行模型優化。
模型優化的超參數調整(Hyperparameter Tuning for Model Optimization)
在機器學習中,在我們選擇了一個模型後,我們可以通過調整模型超參數來對我們的問題進行優化。
首先,超參數是什麼,它們與參數有什麼不同?【4】
• 模型超參數(hyperparameters)被認為是機器學習算法的最好設置,該算法是由數據科學家在訓練之前設置的。例如,隨機森林中樹木的數量,或者k -最近鄰居算法中使用的鄰居數。
• 模型參數(parameters)是模型在訓練過程中學習的內容,例如線性回歸中的權重。
通過改變模型中欠擬合和過擬合的平衡來控制影響模型性能的超參數。當我們的模型不夠複雜(它沒有足夠的自由度)來學習從特徵到目標的映射時,就是欠擬合(Underfitting)。一個欠擬合的模型有很高的偏置(bias),我們可以改變我們的模型使其更複雜來糾正。
過擬合(Overfitting)是當我們的模型基本上擬合了所有訓練數據點的時候。過擬合模型具有很高的方差(variance),我們可以通過正則化(regularization)來限制模型的複雜性來糾正。欠擬合和過擬合模型都不能很好地適用於測試數據(test data)。
•選擇正確的超參數的問題在於,對於每個機器學習問題,最優集都會有所不同!因此,找到最佳設置的唯一方法是在每個新數據集上嘗試一些設置。幸運的是,Scikit-Learn有許多方法可以讓我們高效地評估超參數。此外,Epistasis Lab的TPOT等項目正試圖使用遺傳編程(genetic programming)等方法優化超參數搜索。在這個項目中,我們將使用Scikit-Learning來完成這一任務,但是我們將繼續關注自動ML場景中的更多工作。
我們將要實現的特定超參數調整方法稱為隨機搜索和交叉驗證:
• 隨機搜索(Random Search)是指我們用來選擇超參數的技術。 我們定義一個網格,然後隨機抽樣不同的組合,而不是網格搜索(grid search),我們會徹底地嘗試每一個組合。 (令人驚訝的是,隨機搜索的結果幾乎和網格搜索一樣,但大大縮短了運行時間。)
• 交叉驗證(Cross Validation)是我們用來評估所選超參數組合的技術。 我們使用K折交叉驗證,而不是將訓練集分成單獨的訓練集和驗證集,這會減少我們可以使用的訓練數據量。交叉驗證涉及到將訓練數據分成K個folds,然後經歷一個迭代過程,在這個迭代過程中,我們首先訓練前K-1個folds的數據,然後在第K個fold的數據上進行評估表現。我們重複這個過程K次,在K-fold交叉驗證結束時,我們將每個K次迭代的平均誤差作為最終的性能度量。
K = 5的K-fold交叉驗證的過程如下所示:
使用交叉驗證執行隨機搜索的整個過程是:
建立一個待評估超參數網格
隨機抽樣一組超參數
用選定的組合創建一個模型
使用K-fold交叉驗證評估模型
確定哪些超參數運行得最好
當然,我們實際上並沒有手動做這件事,而是讓Scikit-Learn的RandomizedSearchCV處理所有的工作!
Gradient Boosted Methods(梯度增強方法)由於我們將使用梯度增強回歸模型,我應該至少給出一點背景知識!這個模型是一個集成方法,這意味著它是由許多弱的學習器(weak learners)構建的,在這個例子中是決策樹(individual decision trees)。諸如隨機森林之類的bagging算法會對弱的學習器進行並行訓練,並讓他們投票(vote)進行預測,但像梯度增強這樣的方法,將會依次訓練學習器,並且每個學習器都「集中了」前面的所有錯誤。
增強方法近年來越來越流行,並且頻繁贏得機器學習競賽。梯度增強方法(Gradient Boosting Method)是一種特殊的實現,它使用梯度下降,基於前面的殘差進行連續訓練來最小化成本函數。scikit-learn實現的梯度增強通常被認為效率低於XGBoost等其他庫,但它對於我們的小數據集來說足夠好,並且相當準確。
在Gradient Boosted Regressor中有許多超參數可以調整(tune),您可以查看Scikit-Learn文檔以了解詳細信息。在這個項目中,我們將優化以下超參數:
• loss:用來最小化的損失函數。
• n_estimators:弱學習器(決策樹)的使用數量。
• max_depth:每個決策樹的最大深度。
• min_samples_leaf:決策樹的葉節點所需的最小示例數量。
• min_samples_split:拆分決策樹節點所需的最小示例數量。
• max_features:用於拆分節點的最大特徵數。
我不確定是否有人真正了解所有這些超參數之間的相互作用,找到最佳組合的唯一方法就是try!
在下面的代碼中,我們構建一個超參數網格,創建一個RandomizedSearchCV對象,並在超過25個不同的超參數組合中使用4-fold交叉驗證來執行超參數搜索:
# Loss function to be optimized
loss = ['ls', 'lad', 'huber']
# Number of trees used in the boosting process
n_estimators = [100, 500, 900, 1100, 1500]
# Maximum depth of each tree
max_depth = [2, 3, 5, 10, 15]
# Minimum number of samples per leaf
min_samples_leaf = [1, 2, 4, 6, 8]
# Minimum number of samples to split a node
min_samples_split = [2, 4, 6, 10]
# Maximum number of features to consider for making splits
max_features = ['auto', 'sqrt', 'log2', None]
# Define the grid of hyperparameters to search
hyperparameter_grid = {'loss': loss,
'n_estimators': n_estimators,
'max_depth': max_depth,
'min_samples_leaf': min_samples_leaf,
'min_samples_split': min_samples_split,
'max_features': max_features}
# Create the model to use for hyperparameter tuning
model = GradientBoostingRegressor(random_state = 42)
# Set up the random search with 4-fold cross validation
random_cv = RandomizedSearchCV(estimator=model,
param_distributions=hyperparameter_grid,
cv=4, n_iter=25,
scoring = 'neg_mean_absolute_error',
n_jobs = -1, verbose = 1,
return_train_score = True,
random_state=42)
# Fit on the training data
random_cv.fit(X, y)
在執行搜索之後,我們可以檢查RandomizedSearchCV對象以找到最佳模型:
# Find the best combination of settings
random_cv.best_estimator_
GradientBoostingRegressor(loss='lad', max_depth=5,
max_features=None,
min_samples_leaf=6,
min_samples_split=6,
n_estimators=500)
然後, 我們可以使用這些結果來執行網格搜索, 方法是選擇接近這些最優值的網格參數。但是, 進一步調整不太可能顯著改善我們的模型。作為一般規則, 適當的特徵工程(feature engineering)對模型性能的影響要比最廣泛的超參數調整更大。這是機器學習中的收益遞減法則:特徵工程在大多數情況下會對實現目標有很大的幫助, 而超參數調整通常只會帶來很小的收益。
我們可以嘗試的一個實驗是改變估計器(決策樹)的數量, 同時保持其他超參數穩定。這直接讓我們觀察到這個特定設置的效果。具體實現方法請參閱筆記, 但結果顯示如下:
隨著模型使用的樹的數量增加,訓練和測試的誤差都會減少。 但是,訓練誤差比測試誤差下降得快得多,我們可以看到我們的模型過擬合了:它在訓練數據上表現非常好,但在測試集上無法達到相同的性能。
我們總是期望在測試集上的表現或多或少會有所下降,但是測試集和訓練集的差距太顯著則表明過擬合。我們可以通過獲取更多訓練數據來解決過度擬合問題,或者通過超參數來降低模型的複雜性。在這種情況下,我們將超參數保留在原來的位置,但我鼓勵大家嘗試任何可行的方法來減少過擬合。
對於最終模型,我們將使用800個估計器(estimators),因為這得到了在交叉驗證中的最低誤差。現在,測試這個模型的時間到了!
在測試集進行評估(Evaluating on the Test Set)
作為負責任的機器學習工程師,我們確保不讓我們的模型在任何訓練點上看到測試集的數據。 因此,我們可以使用測試集的表現作為我們的模型在現實世界中部署時的表現。
對測試集進行預測並計算性能是相對簡單的。在這裡,我們將比較默認的梯度增強回歸器(the default Gradient Boosted Regressor)與調參之後的模型的性能:
# Make predictions on the test set using default and final model
default_pred = default_model.predict(X_test)
final_pred = final_model.predict(X_test)
Default model performance on the test set: MAE = 10.0118.
Final model performance on the test set: MAE = 9.0446.
超參數調整將模型的準確率提高了約10%。這取決於使用情況,10%可能是一個巨大的改進,但它需要大量的時間投入!
我們也可以使用Jupyter Notebooks中的%timeit命令來計算訓練這兩個模型(默認模型和調參後模型)需要多長時間。首先是默認模型:
%%timeit -n 1 -r 5
default_model.fit(X, y)
1.09 s ± 153 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)
1秒的訓練時間似乎挺合理的。最終的調參後的模型並沒有那麼快:
%%timeit -n 1 -r 5
final_model.fit(X, y)
12.1 s ± 1.33 s per loop (mean ± std. dev. of 5 runs, 1 loop each)
這證明了機器學習的一個基本特點:它總是一種權衡的遊戲。我們必須不斷平衡準確性與可解釋性,偏差與方差,準確性與運行時間等。這些將最終取決於所要解決的問題。在我們的例子中,相對而言,運行時間增加了12倍是很大的,但從絕對意義上講,它並沒有那麼重要。
一旦我們有了最終的預測值,我們就可以看看他們是否表現出明顯的偏差。左邊是預測值和實際值的密度圖,右邊是殘差的直方圖:
模型預測似乎遵循實際值的分布,儘管密度的峰值出現在訓練集的中值(66)附近,而非密度的真實峰值(接近100)。 殘差幾乎是正態分布,儘管在模型預測值遠低於真實值的情況下,我們會看到一些大的負值。我們將在下一篇文章中深入探討模型的結果。
總結(Conclusions)
在本文中,我們介紹了機器學習工作流程中的幾個步驟:
• 缺失值的插補和特徵的縮放
• 評估和比較幾種機器學習模型
• 使用隨機網格搜索和交叉驗證進行超參數調整
• 評估測試集上的最佳模型
這項工作的結果表明,機器學習適用於我們的任務(使用可用數據預測建築物的Energy Star Score)。使用梯度增強回歸法,我們可以預測測試集的分數在真實值的9.1分以內。 此外,我們還看到,超參數的調優可以提高模型的性能,但是需要相當大的時間成本。這是我們在開發機器學習解決方案時必須考慮的眾多權衡之一。
在下一篇文章中,我們將著眼於我們創建的黑盒子,並試圖理解我們的模型如何進行預測。 我們也將確定影響Energy Star Score的最大因素。雖然我知道我們的模型是準確的,但我們想知道它為什麼會做出預測,以及它告訴我們什麼問題!
原文連結:
https://towardsdatascience.com/a-complete-machine-learning-project-walk-through-in-python-part-two-300f1f8147e2
代碼連結:
https://github.com/WillKoehrsen/machine-learning-project-walkthrough/blob/master/Machine%20Learning%20Project%20Part%202.ipynb
人工智慧領域主題知識資料查看與加入專知人工智慧服務群:
【專知AI服務計劃】專知AI知識技術服務會員群加入與人工智慧領域26個主題知識資料全集獲取
[點擊上面圖片加入會員]
請PC登錄www.zhuanzhi.ai或者點擊閱讀原文,註冊登錄專知,獲取更多AI知識資料!
請加專知小助手微信(掃一掃如下二維碼添加),加入專知主題群(請備註主題類型:AI、NLP、CV、 KG等)交流~
請關注專知公眾號,獲取人工智慧的專業知識!
點擊「閱讀原文」,使用專知