機器學習項目流程(四)選擇並訓練模型


選擇並訓練模型

至此,我們已明確了問題,並對數據進行了預處理。現在我們選擇並訓練一個機器學習模型。

 

在訓練集上訓練模型

這個過程相對來說較為簡單,我們首先訓練一個線性回歸模型:

from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
lin_reg.fit(housing_prepared, housing_labels)

這樣就已完成了一個線性回歸模型的訓練,非常簡單。我們從訓練集里抓幾條數據驗證一下:

sample_data = housing.iloc[:5]
sample_labels = housing_labels.iloc[:5]

sample_data_prepared = full_pipeline.transform(sample_data)
lin_reg.predict(sample_data_prepared)
>array([210644.60459286, 317768.80697211, 210956.43331178,  59218.98886849, 189747.55849879])

list(sample_labels)
>[286600.0, 340600.0, 196900.0, 46300.0, 254500.0]

可以看到預測的精准度並不高,我們可以看一下這個模型的RMSE(均方誤差)的大小:

from sklearn.metrics import mean_squared_error
housing_predictions
= lin_reg.predict(housing_prepared) lin_mse = mean_squared_error(housing_labels, housing_predictions) lin_rmse = np.sqrt(lin_mse) >68628.19819848923

從均方誤差的大小來看,這並不是一個很好的結果,說明模型存在欠擬合。在遇到欠擬合時,說明:

  1. 這些特征沒有提供足夠的信息給模型,導致無法學習到准確的預測模型
  2. 模型本身不適用這個數據集

一般我們可以采取以下方式解決欠擬合問題:

  1. 選擇一個更強大更合適的模型
  2. 給訓練集構造更好的屬性特征
  3. 減少模型的限制(例如加了正則化導致欠擬合)

在這個場景下,模型沒有使用L1/L2 正則,所以先排除第3點。對於第二點,我們可以嘗試加更多的屬性(例如population的對數),不過這里我們首先嘗試第一個方法,選擇另一個更復雜的模型試試。

下面我們試試決策樹,決策樹模型擅長發現復雜的非線性關系:

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor()
tree_reg.fit(housing_prepared, housing_labels)

housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squared_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)
tree_rmse
>0.0

可以看到此模型做出預測后,RMSE的結果是0.0。說明這個模型在訓練集工作良好,但也有過擬合的可能。為了進一步判斷是否過擬合,我們需要用測試集對它進行評估與驗證。

 

使用交叉驗證

其中一種評估決策樹模型的方法是用train_test_split() 將訓練集划分為一個更小的訓練集以及一個驗證集(validation set)。然后使用訓練集訓練模型,並使用驗證集評估模型。

不過另一個更好的辦法是使用K-折交叉驗證(K-fold cross-validation),這個在sklearn 中也提供了。下面的代碼會將訓練集隨機划分成10個互斥子集(每個子集稱為一個fold,這里k=10,也是默認常用的k值),然后訓練並評估模型10次,每次均取9個子集的並集作為訓練數據,剩下的1個子集作為驗證集。最終結果會包含10次validation 的分值:

from sklearn.model_selection import cross_val_score

scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
                         scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)
tree_rmse_scores >array([
67669.73816437, 67362.61970456, 70229.34328631, 68299.62160307, 71291.36213287, 75577.59634532, 72668.53981039, 70226.23940832, 77010.86953522, 69438.29976359])

這里我們在scoring 參數那里指定了一個neg_mean_squared_error,而不是我們之前提到的正均方誤差。這是因為sklearn的交叉驗證方法需要傳入的是一個效應函數(utility function,值越大越好)而不是一個損失函數(cost function,值越小越好)。所以scoring function 這里指定的是均方誤差的負數。

我們看一下結果:

def display_scores(scores):
    print("Scores:", scores)
    print("Mean:", scores.mean())
    print("Standard deviattion:", scores.std())

display_scores(tree_rmse_scores)
>Scores: [69462.00181424 67609.32626575 70422.57362602 69319.8112669
 71825.7583015  75264.10640903 72395.84019687 71141.89336673
 76759.56875965 68894.22449779]
Mean:
71309.51045044875 Standard deviattion: 2729.4780010832424

可以看到決策樹現在的rmse 的結果並沒有之前好了(之前在訓練集上的 rmse 為0),並且結果比線性回歸的結果還要差。通過交叉驗證我們可以獲得多次評估的平均值,並且!還能知道這個評估的精准度(也就是標准差)。隨機數的rmse大約為 71309,一般是±2729(這個變動區間里)。

接下來我們計算一下線性回歸的交叉驗證結果:

lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels,
                            scoring="neg_mean_squared_error", cv=10)
lin_rmse_scores = np.sqrt(-lin_scores)

 
display_scores(lin_rmse_scores)
>Scores: [66782.73843989 66960.118071   70347.95244419 74739.57052552
 68031.13388938 71193.84183426 64969.63056405 68281.61137997
 71552.91566558 67665.10082067]

 Mean: 69052.46136345083

 Standard deviattion: 2731.674001798344

可以看到線性回歸的效果確實略好於決策樹。而決策樹在第一次訓練集上的rsme 的值為0的現象,充分說明了決策樹存在嚴重過擬合。

最后我們試試另一個模型:隨機森林。隨機森林的方法是:在多個隨機子集上訓練多個決策樹,然后取它們預測值的平均值。根據多個模型而構造一個機器學習模型的方法稱為集成學習,這是一個非常有效的手段,可以讓機器學習算法更強大。下面是隨機森林的表現:

from sklearn.ensemble import RandomForestRegressor
 

forest_reg = RandomForestRegressor()
forest_reg.fit(housing_prepared, housing_labels)
forest_prediction = forest_reg.predict(housing_prepared)
forest_rmse = np.sqrt(mean_squared_error(housing_labels, forest_prediction))

forest_rmse
>22260.03021330574

 
forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
                               scoring='neg_mean_squared_error', cv=10)
forest_rmse_scores = np.sqrt(-forest_scores)

display_scores(forest_rmse_scores) >Scores: [
52997.8760788 49958.86106325 52721.44943885 55406.53413082 51444.10657159 55939.86344122 50784.56562956 50979.4567054 56421.26248695 53300.44123253] Mean: 52995.44167789745 Standard deviattion: 2167.186371913895

可以看到效果明顯好了很多,隨機森林的效果看起來很不錯。不過,需要注意的是:在訓練集上的均方誤差仍遠小於驗證集的均方誤差,說明這個模型在訓練集上仍存在過擬合的問題。在這個問題中,我們可以采用以下方式緩解過擬合:

  • 簡化模型,減少模型復雜度
  • 添加限制,例如正則項
  • 獲取更多的訓練數據

當然,在進一步調優隨機森林模型之前,我們仍應該嘗試一下其他機器學習算法(例如SVM+不同的kernel、神經網絡等等),看看這些模型的表現結果(並不需要調參)。我們的目標是:找出幾個(2到5個)可能效果還不錯的模型。再進行下一步調優。

建議大家每次都要保存訓練好的模型,這樣之后可以很快的找到想要的模型。在保存時,需要確保保存了超參數、訓練時的參數、以及交叉驗證的所有結果、(可能)以及預測后的結果。這樣我們在之后進行不同模型對比時,節省不少時間。我們可以通過 Python 的 pickle 模塊保存 sk-learn 的模型。或是使用更高效的sklearn.extenals.joblib,它的性能更好(會序列化大型NumPy 數組):

from sklearn.externals import joblib

joblib.dump(forest_reg, "my_model.pkl")

#load model if necessary
my_model_loaded = joblib.load("my_model.pkl")

至此,我們已介紹了機器學習模型的訓練,下面我們會繼續介紹模型的調優。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM