提升系統(tǒng)
前言叨B叨
大家是不是這會正在忙著搶券,忙著剁手呢? 好吧, 祝你們剁手愉快.
本章包含以下內(nèi)容:
1. 擬合不足和過度擬合
2. 粗暴的解決方案:網(wǎng)格搜索
3. 特征選擇
正文
1. 擬合不足和過度擬合(Overfitting and underfitting)
構(gòu)建機(jī)器學(xué)習(xí)模型的一個(gè)關(guān)鍵挑戰(zhàn)是學(xué)習(xí)如何處理欠擬合和過擬合問題。我們來看一個(gè)房價(jià)的圖表,
其中每個(gè)房子的價(jià)值只根據(jù)房子的大小來確定表谊。一個(gè)好的模型可以按照平滑曲線預(yù)測價(jià)格牵咙。這條曲線是跟隨數(shù)據(jù)的趨勢的。
過度擬合(overfitting)是當(dāng)你的模型記住你的確切的訓(xùn)練數(shù)據(jù)乾胶,但實(shí)際上并沒有找出數(shù)據(jù)中的模式。過度擬合模型可能會像這樣預(yù)測價(jià)格。
換句話說飒筑,該模型太貼合訓(xùn)練數(shù)據(jù)。對任何不在訓(xùn)練數(shù)據(jù)集中的房屋都會做出不恰當(dāng)?shù)念A(yù)測绽昏。如果是這樣,這個(gè)模型根本沒有把握住房價(jià)的套路协屡。它只是記住這些確切的數(shù)據(jù)點(diǎn)。
而擬合不足(underfitting)恰恰相反, 也就是說你的模型太簡單全谤,并沒有完全學(xué)習(xí)數(shù)據(jù)模式肤晓。下面是一個(gè)擬合不足例子。
在這種情況下认然,對于右側(cè)的值模型是正常的,但是左側(cè)的值卻相差很遠(yuǎn)补憾。因?yàn)槟闼褂玫哪P筒粔驈?fù)雜,無法匹配訓(xùn)練數(shù)據(jù)卷员,所以可能會發(fā)生擬合不足的情況余蟹。在這種情況下,我們的模型只是一條直線, 而沒有那一條直線能夠準(zhǔn)確地跟蹤這些房價(jià)的趨勢子刮。
不幸的是威酒,當(dāng)我們構(gòu)建真實(shí)世界的機(jī)器學(xué)習(xí)模型時(shí)窑睁,我們不僅僅要關(guān)注像房子大小這樣的單一功能。我們的模型可能具有數(shù)百或數(shù)千個(gè)特征葵孤。因此担钮,我們不能在圖表上繪制我們所有的數(shù)據(jù),來查看我們的機(jī)器學(xué)習(xí)模型是否合適, 這個(gè)試圖化看起來太復(fù)雜了尤仍。因此箫津,我們不直接看圖表,而是通過查看訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)的錯(cuò)誤率來間接計(jì)算出模型的好壞宰啦。
如果我們的訓(xùn)練數(shù)據(jù)的錯(cuò)誤率很低苏遥,但是我們的測試數(shù)據(jù)集的錯(cuò)誤率非常高,這意味著我們的模型是過度擬合的赡模。
我們知道田炭,因?yàn)檫@個(gè)模型完全符合我們的訓(xùn)練數(shù)據(jù),但并沒有推廣到測試數(shù)據(jù)漓柑。太復(fù)雜的模型會導(dǎo)致過度擬合教硫。我們需要減少模型的復(fù)雜性。通過使用較少的決策樹辆布,使得每個(gè)決策樹更小瞬矩,或者通過選擇簡單的決策樹而不是復(fù)雜決策樹,可以使您的梯度增強(qiáng)模型變得更加復(fù)雜锋玲。但即使這樣模型仍然可能擬合不足景用,原因可能是我們沒有足夠的訓(xùn)練數(shù)據(jù)。如果降低模型的復(fù)雜度并不能解決問題惭蹂,則可能是因?yàn)槟銢]有足夠的訓(xùn)練數(shù)據(jù)來解決問題伞插。
如果我們的訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集的錯(cuò)誤率都很高,那意味著我們的模型是擬合不足,它沒有很好地捕捉到數(shù)據(jù)集中的模式,太簡單的模型就會這樣剿干。
所以您需要使模型更復(fù)雜一些。通過使用更多的決策樹穆刻,或者使每個(gè)決策樹的層級更深些置尔,可以使梯度提升模型更加復(fù)雜。如果我們的訓(xùn)練集和測試集的錯(cuò)誤率都很低氢伟,這意味著我們的模型運(yùn)行良好,而且訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)都是準(zhǔn)確的榜轿。這意味著模型已經(jīng)學(xué)習(xí)到了數(shù)據(jù)背后的真實(shí)模式。
通過調(diào)整模型的超參數(shù)朵锣,我們可以修復(fù)擬合不足和過度擬合的問題谬盐,最終得到一個(gè)合適的模型。
2. 粗暴的解決方案:網(wǎng)格搜索( Grid search)
機(jī)器學(xué)習(xí)模型中的兩個(gè)常見問題是過度擬合和擬合不足诚些。我們通撤煽可以通過調(diào)整模型上的超參數(shù)來解決這個(gè)問題皇型。但問題是機(jī)器學(xué)習(xí)模型有很多超參數(shù)需要調(diào)整。尋找最佳設(shè)置的最好方法通常是通過試驗(yàn)和糾錯(cuò)砸烦,但嘗試所有可能的組合需要花費(fèi)大量的工作弃鸦。
現(xiàn)在讓我們打開源碼中的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'
)
當(dāng)我們創(chuàng)建我們的模型時(shí)幢痘,我們傳入了這些參數(shù)唬格。我們在這里有六個(gè)不同的參數(shù),我們可以調(diào)整颜说,大多數(shù)這些參數(shù)接受任何數(shù)字购岗,所以我們可以嘗試無數(shù)的組合。
解決這個(gè)問題的方法是使用網(wǎng)格搜索(Grid Search)门粪。網(wǎng)格搜索可以列出你想要調(diào)整的每個(gè)參數(shù),然后都嘗試幾遍喊积。用這個(gè)你可以訓(xùn)練和測試每個(gè)參數(shù)組合的模型,最后生成最佳預(yù)測的參數(shù)組合是您應(yīng)該用于真實(shí)模型的一組參數(shù)。幸運(yùn)的是庄拇,scikit-learn完全自動化了這個(gè)過程注服。我們來打開grid_search.py??。這幾乎和train_model.py中的代碼完全一樣措近。
# Create the model
model = ensemble.GradientBoostingRegressor()
第一個(gè)區(qū)別是我們聲明了我們的模型而不傳入任何參數(shù)溶弟。
相反,我們在下面有一個(gè)參數(shù)網(wǎng)格瞭郑。參數(shù)網(wǎng)格為每個(gè)參數(shù)都有一個(gè)數(shù)組辜御。
# 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']
}
對于每個(gè)設(shè)置,我們添加我們想要嘗試的值的范圍屈张。我們在這里設(shè)置的范圍是能夠很好覆蓋大多數(shù)問題的擒权。
一個(gè)好的策略就是對每個(gè)參數(shù)嘗試一些值,在這個(gè)值上增加或減少一個(gè)很大的數(shù)值阁谆,比如1.0到0.3到0.1碳抄,就像我們這里所做的那樣。嘗試非常接近的值如1.0到0.95场绿,沒有多大意義剖效,因?yàn)榻Y(jié)果可能不會有太大的不同。
接下來焰盗,使用網(wǎng)格搜索CV函數(shù)定義網(wǎng)格搜索璧尸。
# Define the grid search we want to run. Run it with four cpus in parallel.
gs_cv = GridSearchCV(model, param_grid, n_jobs=4)
這需要模型對象,參數(shù)表和我們想用來運(yùn)行網(wǎng)格搜索的CPU數(shù)量熬拒。如果您的計(jì)算機(jī)具有多個(gè)CPU爷光,則可以使用它們?nèi)考铀佟=酉聛砼焖冢覀冋{(diào)用CV的fit函數(shù)來運(yùn)行網(wǎng)格搜索蛀序。
# Run the grid search - on only the training data!
gs_cv.fit(X_train, y_train)
這里我們只將訓(xùn)練數(shù)據(jù)傳遞給網(wǎng)格搜索CV功能, 這一點(diǎn)是非常重要的欢瞪。我們不給它訪問我們的測試數(shù)據(jù)集。網(wǎng)格搜索中的CV代表交叉驗(yàn)證(Cross-Validation)哼拔。該功能將自動將訓(xùn)練數(shù)據(jù)切片成較小的子集引有,并將部分?jǐn)?shù)據(jù)用于訓(xùn)練不同模型和不同部分?jǐn)?shù)據(jù)以測試這些模型。
這意味著模型配置沒有看到我們的測試數(shù)據(jù)倦逐,這么做的目的是確保我們對最終模型進(jìn)行完全的盲測譬正。
運(yùn)行網(wǎng)格搜索將需要很長時(shí)間,因?yàn)樗鼘?shí)際上是在對齊網(wǎng)格中為每個(gè)可能的參數(shù)組合訓(xùn)練一個(gè)模型檬姥。完成訓(xùn)練后曾我,將打印出效果最好的模型超參數(shù)。
# Print the parameters that gave us the best result!
print(gs_cv.best_params_)
當(dāng)使用最佳參數(shù)時(shí)健民,它也會告訴我們兩個(gè)數(shù)據(jù)集的平均誤差抒巢。
# 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。在我們的房價(jià)模型中秉犹,
# 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個(gè)原始特征蛉谜,加上使用one-hot編碼創(chuàng)建的新特征,我們總共有63個(gè)特征崇堵。其中一些特征如房屋面積(以平方英尺計(jì)算)型诚,對確定房屋的價(jià)值可能非常重要。其他功能鸳劳,如房子是否有壁爐狰贯,在計(jì)算最終價(jià)格時(shí)可能不太重要,但是有多不重要赏廓?也許有一些特征根本就沒有必要涵紊,我們可以從模型中刪除它們。
通過基于樹的機(jī)器學(xué)習(xí)算法(如梯度增強(qiáng))幔摸,我們可以查看訓(xùn)練模型摸柄,并讓它告訴我們每個(gè)特征在決定最終價(jià)格中的使用頻率。
首先既忆,我們使用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并運(yùn)行它來生成∧蚱叮現(xiàn)在我們可以從我們訓(xùn)練的模型中獲得每個(gè)特征的重要性电媳。為此踏揣,我們調(diào)用以下劃線結(jié)尾的model.feature重要性庆亡。
# Create a numpy array based on the model's feature importances
importance = model.feature_importances_
在scikit-learn中,這步將給我們一個(gè)包含每個(gè)特征的重要性的數(shù)組捞稿。所有特征的重要性的總和加起來為1又谋,因此您可以將此視為百分比評定該特征用于確定房屋價(jià)值的頻率拼缝。
為了使特征列表更易于閱讀,讓我們根據(jù)重要性對它們進(jìn)行排序彰亥。我們將使用numpy的argsort函數(shù)給出指向數(shù)組中每個(gè)元素的數(shù)組索引列表咧七。然后,我們將使用一個(gè)前向循環(huán)打印出每個(gè)特征的名稱和它的重要性任斋。
# 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)))
讓我們來運(yùn)行這個(gè)程序继阻。結(jié)果如下:
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%
我們可以看到,這些最后幾個(gè)特征是房子價(jià)格中最重要的废酷。確定房屋價(jià)格的最重要的因素是規(guī)模瘟檩,建筑年份,車庫的大小澈蟆,臥室的數(shù)量和浴室的數(shù)量墨辛。
如果我們稍微向上滾動,我們可以看到其他因素趴俘,比如房子有多少個(gè)故事睹簇,或者有沒有一個(gè)游泳池,都會影響價(jià)格寥闪,但是它們往往不是那么重要太惠。如果你一路走到名單的最前面,我們可以看到橙垢,有些因素垛叨,如房子是否在新米歇爾市,根本不會影響價(jià)格柜某。但總的來說嗽元,在我們的例子中,這63個(gè)特征中的大部分都被使用了喂击,但是如果你有一個(gè)非常大的模型剂癌,有成千上萬的特征,你可以用這種方法來選擇要保留哪些特征翰绊,哪些特征在下一次訓(xùn)練的時(shí)候可以丟掉佩谷。即使你不排除模型中的任何特征,這也是了解你的模型實(shí)際在做什么的好方法监嗜。
例如谐檀,如果你看到模型認(rèn)為最重要的特征是你認(rèn)為并不重要的特征,也就意味著你的模型還不能很好地工作裁奇。
結(jié)語
下一章將會講解最后一章, 如何使用我們的模型來預(yù)測真實(shí)的數(shù)據(jù), 歡迎關(guān)注.
你的 關(guān)注-收藏-轉(zhuǎn)發(fā) 是我繼續(xù)分享的動力!