機器學習之使用sklearn構造決策樹模型

|舊市拾荒|發表於2019-07-30

一、任務基礎

匯入所需要的庫

import matplotlib.pyplot as plt
import pandas as pd

%matplotlib inline

載入sklearn內建資料集 ,檢視資料描述

from sklearn.datasets.california_housing import fetch_california_housing
housing = fetch_california_housing()
print(housing.DESCR)

 資料集包含房價價格以及影響房價的一些因素

.. _california_housing_dataset:

California Housing dataset
--------------------------

**Data Set Characteristics:**

    :Number of Instances: 20640

    :Number of Attributes: 8 numeric, predictive attributes and the target

    :Attribute Information:
        - MedInc        median income in block
        - HouseAge      median house age in block
        - AveRooms      average number of rooms
        - AveBedrms     average number of bedrooms
        - Population    block population
        - AveOccup      average house occupancy
        - Latitude      house block latitude
        - Longitude     house block longitude

    :Missing Attribute Values: None

This dataset was obtained from the StatLib repository.
http://lib.stat.cmu.edu/datasets/

The target variable is the median house value for California districts.

This dataset was derived from the 1990 U.S. census, using one row per census
block group. A block group is the smallest geographical unit for which the U.S.
Census Bureau publishes sample data (a block group typically has a population
of 600 to 3,000 people).

It can be downloaded/loaded using the
:func:`sklearn.datasets.fetch_california_housing` function.

.. topic:: References

    - Pace, R. Kelley and Ronald Barry, Sparse Spatial Autoregressions,
      Statistics and Probability Letters, 33 (1997) 291-297

檢視資料集維度

housing.data.shape  
(20640, 8)

檢視第一條資料

housing.data[0]
array([   8.3252    ,   41.        ,    6.98412698,    1.02380952,
        322.        ,    2.55555556,   37.88      , -122.23      ])

二、構造決策樹模型

決策樹模型引數:

(1)criterion gini or entropy   基尼係數或者熵
(2)splitter best or random 前者是在所有特徵中找最好的切分點 後者是在部分特徵中(資料量大的時候)
(3)max_features: None(所有),log2,sqrt,N。特徵小於50的時候一般使用所有的特徵
(4)max_depth 資料少或者特徵少的時候可以不管這個值,如果模型樣本量多,特徵也多的情況下,可以嘗試限制下這個決策樹的深度。可以嘗試遍歷max_depth找出最佳。(最常用引數之一)
(5)min_samples_split 如果某節點的樣本數少於min_samples_split,則不會繼續再嘗試選擇最優特徵來進行劃分如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。(最常用引數之一)
(6)min_samples_leaf 這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝,如果樣本量不大,不需要管這個值,大些如10W可是嘗試下
(7)min_weight_fraction_leaf 這個值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝預設是0,就是不考慮權重問題。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分佈類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。
(8)max_leaf_nodes 通過限制最大葉子節點數,可以防止過擬合,預設是"None”,即不限制最大的葉子節點數。如果加了限制,演算法會建立在最大葉子節點數內最優的決策樹。如果特徵不多,可以不考慮這個值,但是如果特徵分成多的話,可以加以限制具體的值可以通過交叉驗證得到。
(9)class_weight 指定樣本各類別的的權重,主要是為了防止訓練集某些類別的樣本過多導致訓練的決策樹過於偏向這些類別。這裡可以自己指定各個樣本的權重如果使用“balanced”,則演算法會自己計算權重,樣本量少的類別所對應的樣本權重會高。
(10)min_impurity_split 這個值限制了決策樹的增長,如果某節點的不純度(基尼係數,資訊增益,均方差,絕對差)小於這個閾值則該節點不再生成子節點。即為葉子節點 。
(11)n_estimators:要建立樹的個數

這些引數都是用來剪枝決策樹,防止決策樹太過龐大或者出現過擬合的現象

這裡只選擇了Longitude(經度)和Latitude(緯度)兩個特徵來構造決策樹模型

from sklearn import tree # 匯入指定模組
dtr = tree.DecisionTreeRegressor(max_depth=2) # 決策分類
dtr.fit(housing.data[:, [6, 7]], housing.target) # x,y值

 可以看出有些引數只需要保持預設即可

DecisionTreeRegressor(criterion='mse', max_depth=2, max_features=None,
                      max_leaf_nodes=None, min_impurity_decrease=0.0,
                      min_impurity_split=None, min_samples_leaf=1,
                      min_samples_split=2, min_weight_fraction_leaf=0.0,
                      presort=False, random_state=None, splitter='best')

決策樹的好處之一就在於通過視覺化顯示可以直觀的看到構造出來的決策樹模型

# 要視覺化顯示,首先需要安裝 graphviz   
# https://graphviz.gitlab.io/_pages/Download/Download_windows.html 下載視覺化軟體
# pip install graphviz

# 設定臨時環境遍歷
import os
os.environ["PATH"] += os.pathsep + 'D:/program files (x86)/Graphviz2.38/bin/'  #注意修改你的路徑

dot_data = tree.export_graphviz(dtr, # 注意這個引數為決策樹物件名稱
                                out_file=None,
                                feature_names=housing.feature_names[6:8], # 還需要指定特徵名
                                filled=True,
                                impurity=False,
                                rounded=True)

顯示決策樹模型

# pip install pydotplus
import pydotplus

graph = pydotplus.graph_from_dot_data(dot_data)
graph.get_nodes()[7].set_fillcolor("#FFF2DD")
from IPython.display import Image
Image(graph.create_png())

  

將資料集劃分為訓練集測試集

from sklearn.model_selection import train_test_split
data_train, data_test, target_train, target_test = train_test_split(
    housing.data, housing.target, test_size=0.1, random_state=42)
dtr = tree.DecisionTreeRegressor(random_state=42)
dtr.fit(data_train, target_train)

dtr.score(data_test, target_test)

得到精度值

0.637355881715626

可以看到,精度值不太高的樣子。

三、隨機森林模型

匯入整合演算法裡面的隨機森林模型庫,在這個例項裡面只是簡單的使用下隨機森林模型。

from sklearn.ensemble import RandomForestRegressor # Regressor 迴歸
# random_state就是為了保證程式每次執行都分割一樣的訓練集和測試集
rfr = RandomForestRegressor( random_state = 42) 
rfr.fit(data_train, target_train)
rfr.score(data_test, target_test)

可以看到隨機森林模型精度要好點 

0.7910601348350835

GridSearchCV,它存在的意義就是自動調參,只要把引數輸進去,就能給出最優化的結果和引數。但是這個方法適合於小資料集,一旦資料的量級上去了,很難得出結果。相當於迴圈遍歷給出的所有的引數來得到最優的結果,十分的耗時。

# from sklearn.grid_search import GridSearchCV
# sklearn.grid_search模組在0.18版本中被棄用,它所支援的類轉移到model_selection模組中。還要注意,
# 新的CV迭代器的介面與這個模組的介面不同。sklearn.grid_search將在0.20中被刪除。
from sklearn.model_selection import GridSearchCV
tree_param_grid = {'min_samples_split':list((3,6,9)),'n_estimators':list((10,50,100))}

# cv 交叉驗證(Cross-validation)的簡寫  代表進行幾次交叉驗證
grid = GridSearchCV(RandomForestRegressor(),param_grid=tree_param_grid,cv=5)
grid.fit(data_train,target_train)
# grid_scores_在sklearn0.20版本中已被刪除,取而代之的是cv_results_。
grid.cv_results_, grid.best_params_, grid.best_score_

可以看到最優化的引數值為'min_samples_split': 3, 'n_estimators': 100,得到精度為0.80多一點(在輸出結果最後一行)

({'mean_fit_time': array([0.91196742, 4.46895003, 8.89996696, 0.90845881, 4.01207662,
         9.11067271, 0.84911356, 4.16957936, 8.08404155]),
  'std_fit_time': array([0.04628971, 0.19323399, 0.36771072, 0.07048984, 0.05280237,
         0.55379083, 0.0599862 , 0.19719896, 0.34949627]),
  'mean_score_time': array([0.00918159, 0.0467237 , 0.08795581, 0.00958099, 0.03958073,
         0.08624392, 0.01018567, 0.03616033, 0.06846623]),
  'std_score_time': array([0.00367907, 0.00559777, 0.00399863, 0.00047935, 0.00082726,
         0.0135891 , 0.0003934 , 0.0052837 , 0.00697507]),
  'param_min_samples_split': masked_array(data=[3, 3, 3, 6, 6, 6, 9, 9, 9],
               mask=[False, False, False, False, False, False, False, False,
                     False],
         fill_value='?',
              dtype=object),
  'param_n_estimators': masked_array(data=[10, 50, 100, 10, 50, 100, 10, 50, 100],
               mask=[False, False, False, False, False, False, False, False,
                     False],
         fill_value='?',
              dtype=object),
  'params': [{'min_samples_split': 3, 'n_estimators': 10},
   {'min_samples_split': 3, 'n_estimators': 50},
   {'min_samples_split': 3, 'n_estimators': 100},
   {'min_samples_split': 6, 'n_estimators': 10},
   {'min_samples_split': 6, 'n_estimators': 50},
   {'min_samples_split': 6, 'n_estimators': 100},
   {'min_samples_split': 9, 'n_estimators': 10},
   {'min_samples_split': 9, 'n_estimators': 50},
   {'min_samples_split': 9, 'n_estimators': 100}],
  'split0_test_score': array([0.79254741, 0.80793267, 0.81163631, 0.78859073, 0.81211894,
         0.81222231, 0.79241065, 0.80784586, 0.80958409]),
  'split1_test_score': array([0.77856084, 0.80047265, 0.80266101, 0.78474831, 0.79898533,
         0.80203702, 0.77912397, 0.79714354, 0.80029259]),
  'split2_test_score': array([0.78105784, 0.80063538, 0.8052804 , 0.78584898, 0.8036029 ,
         0.80240046, 0.78148243, 0.79955117, 0.80072995]),
  'split3_test_score': array([0.79582001, 0.80687008, 0.8100583 , 0.79947207, 0.80958334,
         0.80851996, 0.78633104, 0.80797192, 0.81129754]),
  'split4_test_score': array([0.79103059, 0.8071791 , 0.81016989, 0.78011578, 0.80719335,
         0.81117408, 0.79282783, 0.8064226 , 0.8085679 ]),
  'mean_test_score': array([0.78780359, 0.80461815, 0.80796138, 0.78775522, 0.80629709,
         0.80727103, 0.7864355 , 0.80378723, 0.8060946 ]),
  'std_test_score': array([0.00675437, 0.00333656, 0.00340769, 0.00646542, 0.00460913,
         0.00429948, 0.00556   , 0.00453896, 0.00464337]),
  'rank_test_score': array([7, 5, 1, 8, 3, 2, 9, 6, 4])},
 {'min_samples_split': 3, 'n_estimators': 100},
 0.8079613788142571)

設定上面得到的最優化的引數,構造隨機森林模型

rfr = RandomForestRegressor( min_samples_split=3,n_estimators = 100,random_state = 42)
rfr.fit(data_train, target_train)
rfr.score(data_test, target_test)

可以看出精度相比較上面有了提升。 

0.8088623476993486

四、總結

通過這次案例學習了決策樹模型裡面的一些引數對於決策樹的意義,以及怎麼樣使用視覺化庫來比較方便的展示構造出來的決策樹模型,最後學習到了如何使用模型調參利器GridSearchCV來得到一般機器學習模型裡面最優的引數,達到提升模型精度的目的。 

  

相關文章