機器學習與人工智能基礎:價值估算(第七章-提升系統)

提升系統

Improve Our System

前言叨B叨

大家是不是這會正在忙著搶券,忙著剁手呢? 好吧, 祝你們剁手愉快.
本章包含以下內容:

1. 擬合不足和過度擬合
2. 粗暴的解決方案:網格搜索
3. 特征選擇

正文

1. 擬合不足和過度擬合(Overfitting and underfitting)

構建機器學習模型的一個關鍵挑戰是學習如何處理欠擬合過擬合問題。我們來看一個房價的圖表,


其中每個房子的價值只根據房子的大小來確定。一個好的模型可以按照平滑曲線預測價格。這條曲線是跟隨數據的趨勢的。
過度擬合(overfitting)是當你的模型記住你的確切的訓練數據,但實際上并沒有找出數據中的模式。過度擬合模型可能會像這樣預測價格。

換句話說,該模型太貼合訓練數據。對任何不在訓練數據集中的房屋都會做出不恰當的預測。如果是這樣,這個模型根本沒有把握住房價的套路。它只是記住這些確切的數據點。
而擬合不足(underfitting)恰恰相反, 也就是說你的模型太簡單,并沒有完全學習數據模式。下面是一個擬合不足例子。

在這種情況下,對于右側的值模型是正常的,但是左側的值卻相差很遠。因為你所使用的模型不夠復雜,無法匹配訓練數據,所以可能會發生擬合不足的情況。在這種情況下,我們的模型只是一條直線, 而沒有那一條直線能夠準確地跟蹤這些房價的趨勢。

不幸的是,當我們構建真實世界的機器學習模型時,我們不僅僅要關注像房子大小這樣的單一功能。我們的模型可能具有數百或數千個特征。因此,我們不能在圖表上繪制我們所有的數據,來查看我們的機器學習模型是否合適, 這個試圖化看起來太復雜了。因此,我們不直接看圖表,而是通過查看訓練數據和測試數據的錯誤率來間接計算出模型的好壞。
如果我們的訓練數據的錯誤率很低,但是我們的測試數據集的錯誤率非常高,這意味著我們的模型是過度擬合的。

我們知道,因為這個模型完全符合我們的訓練數據,但并沒有推廣到測試數據。太復雜的模型會導致過度擬合。我們需要減少模型的復雜性。通過使用較少的決策樹,使得每個決策樹更小,或者通過選擇簡單的決策樹而不是復雜決策樹,可以使您的梯度增強模型變得更加復雜。但即使這樣模型仍然可能擬合不足,原因可能是我們沒有足夠的訓練數據。如果降低模型的復雜度并不能解決問題,則可能是因為你沒有足夠的訓練數據來解決問題。

如果我們的訓練數據集和測試數據集的錯誤率都很高,那意味著我們的模型是擬合不足,它沒有很好地捕捉到數據集中的模式,太簡單的模型就會這樣。
所以您需要使模型更復雜一些。通過使用更多的決策樹,或者使每個決策樹的層級更深些,可以使梯度提升模型更加復雜。如果我們的訓練集和測試集的錯誤率都很低,這意味著我們的模型運行良好,而且訓練數據和測試數據都是準確的。這意味著模型已經學習到了數據背后的真實模式。

通過調整模型的超參數,我們可以修復擬合不足和過度擬合的問題,最終得到一個合適的模型。

2. 粗暴的解決方案:網格搜索( Grid search)

機器學習模型中的兩個常見問題是過度擬合和擬合不足。我們通常可以通過調整模型上的超參數來解決這個問題。但問題是機器學習模型有很多超參數需要調整。尋找最佳設置的最好方法通常是通過試驗和糾錯,但嘗試所有可能的組合需要花費大量的工作。

現在讓我們打開源碼中的train_model.py看下。

# Fit regression model

model = ensemble.GradientBoostingRegressor(
    n_estimators=1000,
    learning_rate=0.1,
    max_depth=6,
    min_samples_leaf=9,
    max_features=0.1,
    loss='huber'
)

當我們創建我們的模型時,我們傳入了這些參數。我們在這里有六個不同的參數,我們可以調整,大多數這些參數接受任何數字,所以我們可以嘗試無數的組合。

解決這個問題的方法是使用網格搜索(Grid Search)。網格搜索可以列出你想要調整的每個參數,然后都嘗試幾遍。用這個你可以訓練和測試每個參數組合的模型,最后生成最佳預測的參數組合是您應該用于真實模型的一組參數。幸運的是,scikit-learn完全自動化了這個過程。我們來打開grid_search.py??。這幾乎和train_model.py中的代碼完全一樣。

# Create the model

model = ensemble.GradientBoostingRegressor()

第一個區別是我們聲明了我們的模型而不傳入任何參數。
相反,我們在下面有一個參數網格。參數網格為每個參數都有一個數組。

# Parameters we want to try

param_grid = {
    'n_estimators': [500, 1000, 3000],
    'max_depth': [4, 6],
    'min_samples_leaf': [3, 5, 9, 17],
    'learning_rate': [0.1, 0.05, 0.02, 0.01],
    'max_features': [1.0, 0.3, 0.1],
    'loss': ['ls', 'lad', 'huber']
}

對于每個設置,我們添加我們想要嘗試的值的范圍。我們在這里設置的范圍是能夠很好覆蓋大多數問題的。
一個好的策略就是對每個參數嘗試一些值,在這個值上增加或減少一個很大的數值,比如1.0到0.3到0.1,就像我們這里所做的那樣。嘗試非常接近的值如1.0到0.95,沒有多大意義,因為結果可能不會有太大的不同。
接下來,使用網格搜索CV函數定義網格搜索。

# Define the grid search we want to run. Run it with four cpus in parallel.

gs_cv = GridSearchCV(model, param_grid, n_jobs=4)

這需要模型對象,參數表和我們想用來運行網格搜索的CPU數量。如果您的計算機具有多個CPU,則可以使用它們全部加速。接下來,我們調用CV的fit函數來運行網格搜索。

# Run the grid search - on only the training data!

gs_cv.fit(X_train, y_train)

這里我們只將訓練數據傳遞給網格搜索CV功能, 這一點是非常重要的。我們不給它訪問我們的測試數據集。網格搜索中的CV代表交叉驗證(Cross-Validation)。該功能將自動將訓練數據切片成較小的子集,并將部分數據用于訓練不同模型和不同部分數據以測試這些模型。
這意味著模型配置沒有看到我們的測試數據,這么做的目的是確保我們對最終模型進行完全的盲測。
運行網格搜索將需要很長時間,因為它實際上是在對齊網格中為每個可能的參數組合訓練一個模型。完成訓練后,將打印出效果最好的模型超參數。

# Print the parameters that gave us the best result!

print(gs_cv.best_params_)

當使用最佳參數時,它也會告訴我們兩個數據集的平均誤差。

# Find the error rate on the training set using the best parameters
mse = mean_absolute_error(y_train, gs_cv.predict(X_train))
print("Training Set Mean Absolute Error: %.4f" % mse)

# Find the error rate on the test set using the best parameters
mse = mean_absolute_error(y_test, gs_cv.predict(X_test))
print("Test Set Mean Absolute Error: %.4f" % mse)

3. 特征選擇

我們來打開feature_selection.py。在我們的房價模型中,

# These are the feature labels from our data set
feature_labels = np.array(['year_built', 'stories', 'num_bedrooms', 'full_bathrooms', 'half_bathrooms', 'livable_sqft', 'total_sqft', 'garage_sqft'...'])

如果我們包含18個原始特征,加上使用one-hot編碼創建的新特征,我們總共有63個特征。其中一些特征如房屋面積(以平方英尺計算),對確定房屋的價值可能非常重要。其他功能,如房子是否有壁爐,在計算最終價格時可能不太重要,但是有多不重要?也許有一些特征根本就沒有必要,我們可以從模型中刪除它們。
通過基于樹的機器學習算法(如梯度增強),我們可以查看訓練模型,并讓它告訴我們每個特征在決定最終價格中的使用頻率。
首先,我們使用joblib.load來加載模型。

# Load the trained model created with train_model.py

model = joblib.load('trained_house_classifier_model.pkl')

如果你還沒有生成train house classifier model.pkl文件,只需打開train_model.py并運行它來生成。現在我們可以從我們訓練的模型中獲得每個特征的重要性。為此,我們調用以下劃線結尾的model.feature重要性。

# Create a numpy array based on the model's feature importances

importance = model.feature_importances_

在scikit-learn中,這步將給我們一個包含每個特征的重要性的數組。所有特征的重要性的總和加起來為1,因此您可以將此視為百分比評定該特征用于確定房屋價值的頻率。
為了使特征列表更易于閱讀,讓我們根據重要性對它們進行排序。我們將使用numpy的argsort函數給出指向數組中每個元素的數組索引列表。然后,我們將使用一個前向循環打印出每個特征的名稱和它的重要性。

# Sort the feature labels based on the feature importance rankings from the model
feauture_indexes_by_importance = importance.argsort()

# Print each feature label, from most important to least important (reverse order)
for index in feauture_indexes_by_importance:
    print("{} - {:.2f}%".format(feature_labels[index], (importance[index] * 100.0)))

讓我們來運行這個程序。結果如下:

city_Julieberg - 0.00%
city_New Robinton - 0.00%
city_New Michele - 0.00%
city_Martinezfort - 0.00%
city_Davidtown - 0.04%
city_Rickytown - 0.08%
...
stories - 2.06%
half_bathrooms - 2.14%
full_bathrooms - 3.60%
carport_sqft - 3.95%
num_bedrooms - 4.66%
year_built - 13.18%
garage_sqft - 13.44%
livable_sqft - 16.59%
total_sqft - 16.91%

我們可以看到,這些最后幾個特征是房子價格中最重要的。確定房屋價格的最重要的因素是規模,建筑年份,車庫的大小,臥室的數量和浴室的數量。
如果我們稍微向上滾動,我們可以看到其他因素,比如房子有多少個故事,或者有沒有一個游泳池,都會影響價格,但是它們往往不是那么重要。如果你一路走到名單的最前面,我們可以看到,有些因素,如房子是否在新米歇爾市,根本不會影響價格。但總的來說,在我們的例子中,這63個特征中的大部分都被使用了,但是如果你有一個非常大的模型,有成千上萬的特征,你可以用這種方法來選擇要保留哪些特征,哪些特征在下一次訓練的時候可以丟掉。即使你不排除模型中的任何特征,這也是了解你的模型實際在做什么的好方法。
例如,如果你看到模型認為最重要的特征是你認為并不重要的特征,也就意味著你的模型還不能很好地工作。

結語

下一章將會講解最后一章, 如何使用我們的模型來預測真實的數據, 歡迎關注.

你的 關注-收藏-轉發 是我繼續分享的動力!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,238評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,430評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,134評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,893評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,653評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,136評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,212評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,372評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,888評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,738評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,482評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,179評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,588評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,829評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,610評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,916評論 2 372

推薦閱讀更多精彩內容