【火爐煉AI】機器學習006-用決策樹迴歸器構建房價評估模型

煉丹老頑童發表於2018-08-05

【火爐煉AI】機器學習006-用決策樹迴歸器構建房價評估模型

(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )

最近幾十年,房價一直是中國老百姓心中永遠的痛,有人說,中國房價就像女人的無肩帶文胸,一半人在疑惑:是什麼支撐了它?另一半人在等待:什麼時候掉下去? 而女人,永不可能讓它掉下來。就算快掉下來了,提一提還是又上去了.....

雖然我們不能預測中國房價什麼時候崩盤,但是卻可以用機器學習來構建房價預測模型,下面我們使用波士頓房價資料集來建立一個房價評估模型,通過房子所在的地理位置,人口居住特性等因素來綜合評估房價。


1. 分析資料集

本次模型所使用的資料集來自於波士頓房價資料集官方網站,地址為:(http://www.cs.toronto.edu/~delve/data/boston/bostonDetail.html)。

這個資料集比較小,只有506個樣本,每個樣本有13個features, 1個label,關於這14個屬性的說明如下圖所示:

【火爐煉AI】機器學習006-用決策樹迴歸器構建房價評估模型

所以我們需要構建模型,使用前面的13個特徵來評估最後的MEDV,即使用13個特徵向量來計算房價,這是典型的多元迴歸問題。雖然可以從官網上直接下載這個資料集,但是sklearn中已經整合了該資料集,我們可以直接呼叫。如下程式碼

# 分析資料集
from sklearn import datasets # sklearn自帶的datasets中就有Boston房價資料集
housing_data=datasets.load_boston()
dataset_X=housing_data.data # 獲取影響房價的特徵向量,作為feaure X
dataset_y=housing_data.target # 獲取對應的房價,作為label y
# print(dataset_X.shape) # (506, 13) # 一共有506個樣本,每個樣本有13個features
# print(dataset_y.shape) # (506,)
# print(dataset_X[:5,:]) # 列印看看features的數值型別和大小,貌似已經normalize.

# 將整個資料集劃分為train set 和test set兩部分
from sklearn.utils import shuffle
dataset_X,dataset_y=shuffle(dataset_X,dataset_y)
# print(dataset_X[:5,:]) # 確認dataset_X 的確發生了shuffle
num_split=int(0.8*len(dataset_X))
train_X,train_y=dataset_X[:num_split],dataset_y[:num_split]
test_X,test_y=dataset_X[num_split:],dataset_y[num_split:]
# print(train_X.shape) # (404, 13)
# print(test_X.shape) # (102, 13)

# 上面的資料集劃分也可以採用下面的方法:
# from sklearn.model_selection import train_test_split
# dataset_y=dataset_y[:,np.newaxis]
# dataset=np.hstack((dataset_X,dataset_y))
# print(dataset.shape)
# print(dataset[:,:3])
# train_set,test_set=train_test_split(dataset,test_size=0.2,random_state=37)
# print(train_set.shape) # (404, 14)
# print(test_set.shape) # (102, 14)

複製程式碼

上述程式碼首先呼叫sklearn.load_boston()來獲取波士頓房價資料集,然後將該資料集劃分為兩部分,其中train set佔據80%(即404個樣本),test set佔據20%(102個樣本)。在檢視資料集中前面五行的結果時,發現整個資料集已經Normalize,故而此處我們沒有必要進行歸一化。


2. 構建決策樹模型

決策樹(DecisionTree, DT)是一種常見的用於分類和迴歸的非引數監督學習方法,目標是建立一個模型,通過從資料特性中推匯出簡單的決策規則來預測目標變數的值。

決策樹模型的優點在於:1,簡單容易理解,數結構可以視覺化表達。2,需要很少的資料準備,其他技術通常需要資料標準化,需要建立虛擬變數,並刪除空白值。3,能夠處理多輸出問題。4,相比於使用神經網路的模型,決策樹是白盒模型,結果很容易解釋。

決策樹模型的缺點在於:1,決策樹學習可能會生成過於複雜的數結構,不能代表普遍的規則,即模型容易過擬合,修剪機制,設定葉子節點所需的最小樣本數目或設定數的最大深度是避免決策樹過擬合的必要條件。2,決策樹可能不穩定,因為資料中的小變化可能導致生成完全不同的樹。這個問題可以通過在一個集合中使用多個決策樹來減輕。3,實際的決策樹學習演算法是基於啟發式演算法的,例如在每個節點上進行區域性最優決策的貪婪演算法。這種演算法不能保證返回全域性最優決策樹。通過在集合學習中訓練多個樹,可以減少這種情況,在這裡,特徵和樣本是隨機抽取的。4,有些概念很難學習,因為決策樹無法很容易地表達它們,例如XOR、奇偶性或多路複用問題。

說了這麼多廢話,直接看程式碼吧。。。

# 構建決策樹迴歸模型
from sklearn.tree import DecisionTreeRegressor
decision_regressor=DecisionTreeRegressor(max_depth=4) # 最大深度確定為4
decision_regressor.fit(train_X,train_y) # 對決策樹迴歸模型進行訓練

# 使用測試集來評價該決策樹迴歸模型
predict_test_y=decision_regressor.predict(test_X)

import sklearn.metrics as metrics
print('決策樹迴歸模型的評測結果----->>>')
print('均方誤差MSE:{}'.format(
    round(metrics.mean_squared_error(predict_test_y,test_y),2)))
print('解釋方差分:{}'.format(
    round(metrics.explained_variance_score(predict_test_y,test_y),2)))
複製程式碼

-------------------------------------輸---------出--------------------------------

決策樹迴歸模型的評測結果----->>> 均方誤差MSE:13.33 解釋方差分:0.81

--------------------------------------------完-------------------------------------

########################小**********結###############################

1. 決策樹迴歸模型的構建非常簡單,和線性迴歸器的構建類似,使用DecisionTreeRegressor獲取一個迴歸器物件即可,模型的訓練使用fit函式,預測使用predict函式即可。

2. 簡單的決策樹迴歸模型得到的MSE比較大,解釋方差分結果也不理想,說明這個模型還有很大的優化空間。

#################################################################


3. 決策樹模型的優化

一般的,可以先從資料集上優化,但本專案的資料集是非常成熟的案例,進一步優化的空間不大,所以只能從模型上下手。此處我採用兩種優化方法,第一種是優化決策樹模型中的各種引數,比如優化max_depth,判斷是否可以改進MSE,第二種方式是使用AdaBoost演算法來增強模型的準確性。

# 第一種優化方法:改變max depth來降低MSE,提高解釋方差分
for depth in range(2,12):
    decision_regressor_test=DecisionTreeRegressor(max_depth=depth) 
    decision_regressor_test.fit(train_X,train_y)
    predict_test_y2=decision_regressor_test.predict(test_X)
    print('depth: {}, MSE: {:.2f}, EVS: {:.2f}'.format(
        str(depth), metrics.mean_squared_error(predict_test_y2,test_y),
        metrics.explained_variance_score(predict_test_y2,test_y)))
複製程式碼

-------------------------------------輸---------出--------------------------------

depth: 2, MSE: 23.83, EVS: 0.62 depth: 3, MSE: 20.98, EVS: 0.68 depth: 4, MSE: 13.33, EVS: 0.81 depth: 5, MSE: 13.00, EVS: 0.83 depth: 6, MSE: 14.36, EVS: 0.83 depth: 7, MSE: 11.73, EVS: 0.86 depth: 8, MSE: 16.18, EVS: 0.83 depth: 9, MSE: 15.74, EVS: 0.83 depth: 10, MSE: 14.67, EVS: 0.83 depth: 11, MSE: 15.02, EVS: 0.84

--------------------------------------------完-------------------------------------

# 第二種優化方法:通過AdaBoost演算法來提高模型準確度
from sklearn.ensemble import AdaBoostRegressor
ada_regressor=AdaBoostRegressor(DecisionTreeRegressor(max_depth=7),n_estimators=400)
ada_regressor.fit(train_X,train_y)

# 檢視使用AdaBoost演算法後模型的MSE 和EVS
predict_test_y=ada_regressor.predict(test_X)

import sklearn.metrics as metrics
print('AdaBoost決策樹迴歸模型的評測結果----->>>')
print('均方誤差MSE:{}'.format(
    round(metrics.mean_squared_error(predict_test_y,test_y),2)))
print('解釋方差分:{}'.format(
    round(metrics.explained_variance_score(predict_test_y,test_y),2)))
複製程式碼

-------------------------------------輸---------出--------------------------------

AdaBoost決策樹迴歸模型的評測結果----->>> 均方誤差MSE:7.87 解釋方差分:0.9

--------------------------------------------完-------------------------------------

########################小**********結###############################

1,兩種優化方法:第一種通過優化max_depth可以發現,在depth=7時得到的MSE最小,且解釋方差分最大,故而認定max_depth=7.

2,第二種通過AdaBoost增強演算法來優化模型,得到的MSE(7.87)比depth優化最好的MSE(11.73)要小很多,且解釋方差分也有了較大提高,說明優化效果比較好。

3,AdaBoost(Adaptive boosting)演算法是一種自適應的利用其他系統來增強模型準確性的演算法,將不同版本的演算法結果進行組合,用加權彙總的方式獲得最終結果。AdaBoost演算法在每個階段獲取的資訊都會反饋到模型中,這樣學習器就可以在後一階段重點訓練難以分類的樣本。

4,當然,對於本模型,還可以繼續優化,比如優化決策樹的結構,優化決策樹的其他引數等。

#################################################################


4. 特徵的相對重要性

本專案共有13個特徵,但這13個特徵對於房價的影響肯定是不同的,比如從直觀上來看,學區房對房價影響肯定比較大,所以可以計算出各種不同特徵對模型的影響,進而在特徵比較複雜的情況下,可以忽略掉影響比較小的特徵。

如下兩部分程式碼可以將各種特徵的相對重要性繪製到圖中。

# 計算不同特徵的相對重要性
def plot_importances(feature_importances, title, feature_names):
    '''將feature_importance繪製到圖表中,便於觀察,
    並把重要性大於5的特徵列印出來'''
    # 將重要性都歸一化為0-100之內
    feature_importances=100.0*(feature_importances/max(feature_importances))
    
    # 將得分從高到低排序
    index_sorted=np.flipud(np.argsort(feature_importances))
    # 讓X座標軸上的標籤居中顯示
    pos=np.arange(index_sorted.shape[0])+0.5
    
    # 畫條形圖
    plt.figure()
    plt.bar(pos,feature_importances[index_sorted],align='center')
    plt.xticks(pos,feature_names[index_sorted])
    plt.ylabel('Relative Importance')
    plt.title(title)
    
    # 把重要性結果列印出來
    print('{} importance list------>>>>>'.format(title))
    for importance,name in zip(feature_importances[index_sorted],
                               feature_names[index_sorted]):
        if importance>5:
            print('feature:{}, importance: {:.2f}'.format(name,importance))
複製程式碼
decision_regressor7=DecisionTreeRegressor(max_depth=7) # 最大深度確定為7
decision_regressor7.fit(train_X,train_y) # 對決策樹迴歸模型進行訓練
plot_importances(decision_regressor7.feature_importances_,
                 'DT regressor',housing_data.feature_names)
plot_importances(ada_regressor.feature_importances_,
                 'AdaBoost Optimized DT regressor',housing_data.feature_names)
複製程式碼

-------------------------------------輸---------出--------------------------------

DT regressor importance list------>>>>> feature:LSTAT, importance: 100.00 feature:RM, importance: 52.24 feature:DIS, importance: 15.97 feature:PTRATIO, importance: 5.00 AdaBoost Optimized DT regressor importance list------>>>>> feature:LSTAT, importance: 100.00 feature:RM, importance: 46.72 feature:DIS, importance: 21.80 feature:TAX, importance: 7.34 feature:AGE, importance: 7.29 feature:CRIM, importance: 6.51 feature:NOX, importance: 5.32 feature:PTRATIO, importance: 5.29

--------------------------------------------完-------------------------------------

決策樹迴歸器得到的特徵重要性圖

AdaBoost優化後得到的特徵重要性圖

########################小**********結###############################

1,通過上面兩幅圖的比較,可以看出,各種特徵對模型的相對重要性變化很大,兩種模型都發現最重要的特徵是LSTAT(這和書本《Python機器學習經典例項》中不一樣。

2,但AdaBoost增強演算法貌似能夠提升其他小特徵的相對重要性,而且兩種模型中特徵重要性排序也不一樣。

#################################################################


注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。

參考資料:

1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯

相關文章