機(jī)器學(xué)習(xí)與人工智能基礎(chǔ):價(jià)值估算(第七章-提升系統(tǒng))

提升系統(tǒng)

Improve Our System

前言叨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)行它來生成?,F(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ù)分享的動力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容