決策樹
概述
▒ 樹模型
▨ 從根節點一步一步走到葉子節點 ( 決策 )html
▨ 全部數據都會落在葉子節點, 既能夠作分類也能夠作迴歸node
▒ 樹的組成
▨ 根節點 - 第一個選擇點git
▨ 非葉子節點與分支 - 中間過程算法
▨ 葉子節點 - 最終的決策結果windows
▒ 節點
▨ 節點至關於在數據中進行切一刀 ( 切分兩部分 - 左右子樹 )數組
▨ 節點越多越好嗎? - dom
▒ 決策樹的訓練和測試
▨ 訓練階段 - 從給定的訓練集構造一棵樹 ( 從根節開始選擇特徵, 如何進行特徵切分 )工具
▨ 測試階段 - 根據構造出來的樹模型從上到下走一遍gitlab
▨ 難點 - 測試階段較爲容易, 而訓練階段並不簡單測試
▒ 如何切分特徵 ( 選擇節點 )
▨ 問題 - 一個數據集中可能存在多個特徵的時候, 選擇那個節點特徵做爲根節點進行分支, 以及其餘特徵分支的選擇順序都是問題
▨ 目標 - 須要經過一種衡量標準, 來計算不一樣特徵進行分支選擇後的分類狀況, 找出最好的那個當作根節點, 以此類推
決策樹算法 - 信息增益
▒ 衡量標準 - 熵
▨ 熵 - 表示隨機變量的不肯定性的度量 ( 簡單來講就是混亂程度 )
當 p = 0 或者 p = 1 的時候, H(p) = 0, 隨機變量徹底沒有不肯定性
當 p = 0.5 時, H(p) = 1 此時,隨機變量的不肯定性最大
▨ 公式 -
▨ 栗子 - a = [1,1,1,2,1,2,1,1,1] , b = [1,5,6,7,5,1,6,9,8,4,5] a 的熵更底, 由於 a 的類別較少, 相對 b 就更穩定一些
▨ 信息增益 - 表示特徵 X 使 Y 的不肯定性減小的程度 (分類後的專注性, 但願分類後的結果同類在一塊兒)
▒ 示例
▨ 數據 - 14 天打球狀況
▨ 特徵 - 4 種天氣因素
▨目標 - 構建決策樹
▨ 根節點選擇
14天的記錄中, 有 9 天打球, 5 天沒打球, 熵爲
演示 - outlook 特徵 - 天氣
suuny 的機率是 5/14 , 熵 是 0.971
overcast 的機率是 4/14 , 熵 是 0
rainy 的機率是 5/14 , 熵 是 0.971
熵值計算 : 5/14*0.971 + 4/14*0 + 5/14*0.971 = 0.693
信息增益 : 系統的 熵值從原始的 0.940 降低到了 0.693 , 增益爲 0.247
以此類推動行處理, 選出根節點而後再從剩餘的特徵中選擇次根節點往下到僅剩最後一個特徵,
▒ 總結
▨ 弊端
如 id 這樣的惟一標識特徵列, 會讓熵值計算爲 0 被視爲最大信息增益 ,
可是 id 僅僅是編號標識對信息的模型無任何影響實則無效項
▨ 解決
信息增益率 - 解決信息增益問題, 考慮自身熵
GINI 係數 - ( 和熵的衡量標準相似, 計算方式不一樣 )
特殊處理
▒ 連續值處理
本質上就上 離散化
對序列遍歷而後尋找離散點進行二分
▒ 剪枝策略
▨ 爲毛
決策樹擬合風險過大, 理論上能夠徹底分開數據, 讓每一個葉子節點都只有一個命中數據
訓練集中的數據這樣完美命中, 可是在測試集中可能會出現不適配等各類異常狀況
▨ 策略
預剪枝 - 邊簡歷決策樹邊進行剪枝操做 ( 更實用 )
後剪枝 - 當創建完決策樹後進行剪枝操做
▨ 預剪枝
限制 深度, 葉子節點個數, 葉子節點樣本數, 信息增益量等
▨ 後剪枝
經過必定的衡量標準 - 葉子越多, 損失 (C(T)) 越大
代碼實現
▒ 模塊引入
%matplotlib inline import matplotlib.pyplot as plt import pandas as pd
▒ 數據集準備
▨ 下載
數據集經過 sklearn 模塊內置的 房價預測數據集
from sklearn.datasets.california_housing import fetch_california_housing housing = fetch_california_housing() print(housing.DESCR)
▨ 結構
▒ 模型生成
▨ 實例化模型
實例化樹模型 , 指定最大深度, .fit 構造決策樹, 傳入參數分別表示 x 和 y 值
from sklearn import tree dtr = tree.DecisionTreeRegressor(max_depth = 2) dtr.fit(housing.data[:, [6, 7]], housing.target)
◈ criterion 評估標準 - gini / entropy
指定 gini 係數或者熵值做爲評估標準
◈ splitter 特徵選擇 - best / random
前者是在全部特徵中找最好的切分點 後者是在部分特徵中(數據量大的時候) 通常都默認是 best
◈ max_features 特徵數 - None / log2 / sqrt / n (數字)
特徵小於50的時候 (通常使用全部 - None , 即默認)
◈ max_depth 最大深度 - n (數字)
數據少或者特徵少的時候能夠無論這個值,若是模型樣本量多,特徵也多的狀況下,能夠嘗試限制下
◈ min_samples_split 最大葉子節點容量 - n (數字)
某節點的樣本數少於此參數,則不繼續再嘗試選擇最優特徵來進行劃分, 樣本量不大時無需設置
更適用於大規模的數據集避免過擬合
◈ min_samples_leaf 最小葉子節點容量 - n (數字)
某葉子節點數目小於樣本數,則會和兄弟節點一塊兒被剪枝,樣本量小無需此參數
◈ min_weight_fraction_leaf
限制了葉子節點全部樣本權重和的最小值,若是小於這個值,則會和兄弟節點一塊兒被剪枝默認是0
若是咱們有較多樣本有缺失值,或者分類樹樣本的分佈類別誤差很大,就可引入樣本權重
◈ max_leaf_nodes
經過限制最大葉子節點數,能夠防止過擬合,默認是"None」,即不限制最大的葉子節點數。
若是加了限制,算法會創建在最大葉子節點數內最優的決策樹
特徵很少時不考慮此參數,可是若是特徵分紅多的話,能夠加以限制具體的值能夠經過交叉驗證獲得。
◈ class_weight
指定樣本各種別的的權重,主要是爲了防止訓練集某些類別的樣本過多致使訓練的決策樹過於偏向這些類別。
這裏能夠本身指定各個樣本的權重若是使用「balanced」,則算法會本身計算權重,樣本量少的類別所對應的樣本權重會高。
◈ min_impurity_split
限制決策樹的增加,若是某節點的不純度(基尼係數,信息增益,均方差,絕對差)小於這個閾值則該節點再也不生成子節點。即爲葉子節點 。
◈ n_estimators:
要創建樹的個數
▒ 可視化處理
▨ 下載可視化工具 graphviz 下載地址
▨ 配置環境變量, 能夠手動指定, 也能夠代碼實現
import os os.environ["PATH"] += os.pathsep + 'C:/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 )
▨ 安裝 dot 可視化工具模塊 - pydotplus 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())
▨ 視狀況能夠進行保存等操做, 保存爲 png 格式更加清晰一些
graph.write_png("dtr_white_background.png")
▒ 測試數據集, 參數選擇
▨ 切分數據集
train_test_split 的參數傳入 x , y 以及 test_size 表示測試集比例大小, random_state 指定一個值做爲seed標識方便用於往後方便復現,
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
▨ 選擇參數
參數的選擇是沒法一上來就能夠肯定最優參數的, 並且參數比較多, 怎麼選擇組合就是個問題了
所以須要進行必定程度的組合, 本質上就是參數集之間的交叉組合的遍歷比對, GridSearchCV 的原理就是於此進行的封裝
傳入參數, 算法 ( 算法實例 ) , 參數候選項 ( 可字典形式 ), 交叉驗證次數 ( cv , 切分段數 )
from sklearn.ensemble import RandomForestRegressor rfr = RandomForestRegressor(random_state = 42) rfr.fit(data_train, target_train) rfr.score(data_test, target_test) # 0.7910601348350835
from sklearn.model_selection import GridSearchCV tree_param_grid = { 'min_samples_split': list((3,6,9)),'n_estimators':list((10,50,100))} grid = GridSearchCV(RandomForestRegressor(),param_grid=tree_param_grid, cv=5) grid.fit(data_train, target_train) grid.cv_results_, grid.best_params_, grid.best_score_
比對結果, 測試得出 3, 100 爲這組參數的最佳組合, 實際中會有更多的參數,這裏僅僅選取了兩組參數組進行比對
({'mean_fit_time': array([0.86073136, 4.28014984, 8.4557868 , 0.78763537, 3.94817624, 7.93624506, 0.75090647, 3.77697754, 7.65297484]), 'std_fit_time': array([0.05199331, 0.05060905, 0.08284658, 0.02222307, 0.04220675, 0.11099333, 0.0248957 , 0.05866979, 0.12467865]), 'mean_score_time': array([0.01007967, 0.05109978, 0.09502277, 0.00928087, 0.03622227, 0.07206926, 0.00758247, 0.03662882, 0.07186236]), 'std_score_time': array([0.00038016, 0.00981283, 0.011958 , 0.00261602, 0.00086917, 0.00067269, 0.00037106, 0.0076475 , 0.01476559]), '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.78845443, 0.81237387, 0.81156962, 0.79533209, 0.80854898, 0.80978258, 0.78914336, 0.80923727, 0.80858502]), 'split1_test_score': array([0.77014582, 0.79941449, 0.80094417, 0.78184821, 0.79978092, 0.79862554, 0.78052651, 0.7982624 , 0.79905119]), 'split2_test_score': array([0.78529369, 0.79965572, 0.80365713, 0.79374636, 0.80051057, 0.80568461, 0.78434117, 0.80059003, 0.80257161]), 'split3_test_score': array([0.79563203, 0.8098409 , 0.80998308, 0.79636012, 0.80891923, 0.8114358 , 0.79592629, 0.80754011, 0.81196788]), 'split4_test_score': array([0.781435 , 0.80752598, 0.8088186 , 0.78937079, 0.80655187, 0.80661464, 0.79724106, 0.80598448, 0.80706041]), 'mean_test_score': array([0.78419242, 0.80576255, 0.80699476, 0.79133173, 0.80486251, 0.80642881, 0.78943566, 0.80432312, 0.80584737]), 'std_test_score': array([0.00842779, 0.00531127, 0.00402334, 0.00530843, 0.00394113, 0.00442255, 0.00645683, 0.00419352, 0.00454625]), 'rank_test_score': array([9, 4, 1, 7, 5, 2, 8, 6, 3])}, {'min_samples_split': 3, 'n_estimators': 100}, 0.8069947626655254)