决策树原理详解及python代码实现
決策樹算法(信貸中常用來尋找規則)
- 1、算法原理
- 1.1 ID3(多叉樹分類)
- 1.2 C4.5(多叉樹分類)
- 1.3 Cart(二叉樹分類+回歸)
- 2、ID3、C4.5與Cart比較
- 3、算法優缺點
- 4、算法需要注意的點
- 5、python代碼實現
- 5.1導入相關包
- 5.2 讀取數據并數據處理
- 5.3 模型訓練
- 5.4 評估指標
- 5.4 決策樹以圖的形式輸出
1、算法原理
1.1 ID3(多叉樹分類)
信息熵:Ent(D)=?∑i=1npilogpiEnt(D)=-\sum_{i=1}^np_ilogp_iEnt(D)=?∑i=1n?pi?logpi?其中n為類別,pip_ipi?為每個類別的概率,DDD為某個特征,越小越確定
信息增益:Gain(D,a)=Ent(D)=?∑v=1v∣Dv∣∣D∣Ent(Dv)Gain(D,a)=Ent(D)=-\sum_{v=1}^v\frac{|D^v|}{|D|}Ent(D^v)Gain(D,a)=Ent(D)=?∑v=1v?∣D∣∣Dv∣?Ent(Dv)越大純度提升越大,所以分裂argmaxGain(D,a)argmaxGain(D,a)argmaxGain(D,a)
eg.15個樣本,9個1和6個0;有個特征A(取值A1A_1A1?、A2A_2A2?、A3A_3A3?,其中A1A_1A1?(3個1,2個0),其中A2A_2A2?(2個1,3個0)其中A3A_3A3?(4個1,1個0))
Ent(A)=?(915?log2915+615?log2615)=0.971Ent(A)=-(\frac{9}{15}*log_2\frac{9}{15}+\frac{6}{15}*log_2\frac{6}{15})=0.971Ent(A)=?(159??log2?159?+156??log2?156?)=0.971
Gain(A,a)=0.971?(515Ent(A1)+515Ent(A2)+515Ent(A3))=0.083Gain(A,a)=0.971-(\frac{5}{15}Ent(A1)+\frac{5}{15}Ent(A2)+\frac{5}{15}Ent(A3))=0.083Gain(A,a)=0.971?(155?Ent(A1)+155?Ent(A2)+155?Ent(A3))=0.083
- ID3在相同條件下取值較多的比較少的信息增益要大(2個值為12\frac{1}{2}21?,3個值為13\frac{1}{3}31?,但是3個信息增益會更大)
- ID3沒有考慮連續特征
- ID3對缺失值未考慮
需要懲罰取值較多的信息增益,引出了信息增益率,即C4.5的算法
1.2 C4.5(多叉樹分類)
IV(a)=?∑v=1v∣Dv∣∣D∣log2∣Dv∣∣D∣IV(a)=-\sum_{v=1}^v\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|}IV(a)=?∑v=1v?∣D∣∣Dv∣?log2?∣D∣∣Dv∣? 特征取值越多,IV(a)IV(a)IV(a)越大
信息增益率:Gain_ratio(D,a)=Gain(D,a)IV(a)Gain\_ratio(D,a)=\frac{Gain(D,a)}{IV(a)}Gain_ratio(D,a)=IV(a)Gain(D,a)? argmaxGain_ratio(D,a)Gain\_ratio(D,a)Gain_ratio(D,a)
- 如果為連續型變量,先從大到小排序,分別取2個中值(均值)作為劃分點計算
引出了分類+回歸的決策樹
1.3 Cart(二叉樹分類+回歸)
Gini(D)=1?∑i=1npi2Gini(D)=1-\sum_{i=1}^np_i^2Gini(D)=1?∑i=1n?pi2? 反映隨機抽2個樣本,不一致的概率,越小越好(越純)
Ginisplit(D)=1?∑v=1v∣Dv∣∣D∣Gini(Dv)Gini_{split}(D)=1-\sum_{v=1}^v\frac{|D^v|}{|D|}Gini(D^v)Ginisplit?(D)=1?∑v=1v?∣D∣∣Dv∣?Gini(Dv)
eg.Age(youth(5)、middle(5)、senior(4)),以youth(5)和middle+senior(9)分割為例:
Ginisplit(Age)=514[1?[(35)2+(25)2]]+914[1?[(29)2+(79)2]]=0.39Gini_{split}(Age)=\frac{5}{14}[1-[(\frac{3}{5})^2+(\frac{2}{5})^2]]+\frac{9}{14}[1-[(\frac{2}{9})^2+(\frac{7}{9})^2]]=0.39Ginisplit?(Age)=145?[1?[(53?)2+(52?)2]]+149?[1?[(92?)2+(97?)2]]=0.39
如果為連續性變量處理方式與C4.5相同
回歸mse:
- 根據每一個連續值作為劃分點(或用分類的方式取均值作為劃分點),將其劃分S1S_1S1?、S2S_2S2?
- 計算每個分支(S1S_1S1?、S2S_2S2?)的均值。 mean=sum(s1或s2里真實值)該集合樣本總數mean=\frac{sum(s_1或s_2里真實值)}{該集合樣本總數}mean=該集合樣本總數sum(s1?或s2?里真實值)?即為該分支的預測值
- 計算S1S_1S1?、S2S_2S2?的mse的和。 mse=(該集合每一個樣本真實值?mean)2mse=(該集合每一個樣本真實值-mean)^2mse=(該集合每一個樣本真實值?mean)2
注:實踐證明GiniGiniGini和GainGainGain效果差不多
2、ID3、C4.5與Cart比較
| 連續值處理 | ×\times× | √\surd√ | √\surd√ |
| 缺失值處理 | ×\times× | √\surd√ | √\surd√ |
| 剪枝 | ×\times× | √\surd√ | √\surd√ |
- ID3、C4.5與Cart特征選擇只選一個特征。但大多數由一組特征決定。這樣得到的決策樹更準確(oc1)
- 樣本發生一點改變,樹的結構可能會發生劇烈的變化
3、算法優缺點
一、優點:
- 簡單直觀,生成的決策樹可解釋性強
- 不需要數據預處理(例如歸一化處理,但封裝的scikit-learn需要處理缺失值與字符型變量)
- 可以處理多維度多分類問題
一、缺點:
- 容易過擬合
- 樣本發生改變可能導致完全不同的樹
- 樣本不平衡時,樹會偏向于類別較多的一類
4、算法需要注意的點
決策樹的構建過程中出現過擬合的原因及解決方法
原因:
- 在構建過程中沒有進行合理的限制(如樹的深度等)
- 樣本中有噪聲數據,沒有進行有效的剔除
- 變量較多也容易產生過擬合
解決方法: 剪枝、限制深度、RF、正則化等
決策樹如何處理缺失值
1、使用權重方法重構。(可認為以前1?Gain*Gain?Gain,現在無缺失比率?Gain*Gain?Gain)訓練時特征出現缺失怎么處理(劃分)即不考慮缺失,然后重賦權重
2、將缺失(劃分變量)的樣本中分別放到不同分支再進行分支。缺失變量樣本的歸屬分支問題
3、同時探查所有分支,然后算每個類別的概率,取概率最大的類別賦值該樣本。測試集中缺失處理
決策樹遞歸終止的條件
1、所有子集被正確分類;2、沒有合適的特征選擇或信息增益(信息增益率/Gini)很小
決策樹的變量重要性
如樣本分裂占比?*?Gini/信息增益比
5、python代碼實現
5.1導入相關包
import numpy as np import pandas as pd from sklearn.preprocessing import LabelEncoder #分類變量編碼包 from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier import variable_iv as vi import Logistic_model as lmimport os os.chdir('E:/wyz/Desktop/cart/') os.environ["PATH"] += os.pathsep + 'D:/Program Files (x86)/Graphviz2.38/bin/'#決策樹可視化的包5.2 讀取數據并數據處理
data = pd.read_excel('ceshi.xlsx',sheet_name = 'Sheet2') #分類變量編碼 from sklearn.preprocessing import LabelEncoder le = LabelEncoder() str_variable = list(data.dtypes[data.dtypes.values == object].index) for col in str_variable: data[col] = le.fit_transform(data[col].astype(str)) #在單變量分析的基礎上填充缺失值(看哪一組的1的比率最接近于缺失值的那一組) data['var1'] = data['var1'].fillna(0.42089) data['var2'] = data['var2'].fillna(125.854) #劃分數據集 y = data_model['target'] x = data_model.drop('target', axis=1) x_train, x_test, y_train, y_test = train_test_split(x, y,random_state=0,train_size=0.7)5.3 模型訓練
#建立模型(min_samples_leaf和min_samples_split需要慎重選擇)(和傳統決策樹有很大區別) model_tree = DecisionTreeClassifier(criterion='gini',#劃分標準splitter='best',#特征劃分標準max_depth=3,#樹的最大深度min_samples_split=20,#劃分所需要的最小樣本數min_samples_leaf=10,#分到每個葉子最小樣本數max_features=None,#用于參與劃分的變量個數 max_leaf_nodes=None,#最大葉子節點數 min_impurity_decrease=0.0,#節點劃分最小不純度 min_weight_fraction_leaf=0.0,#葉子節點最小的樣本權重和presort=False,#進行擬合前是否預分數據來加快樹的構建random_state=None, )#建模要class_weight='balanced' model_tree.fit(x_train, y_train)5.4 評估指標
test_proba = pd.DataFrame(model_tree.predict_proba(x_test))[1].values#預測為0的概率 print('測試集AUC: %.4f'%roc_auc_score(y_test,test_proba))#AUC,預測為概率#變量重要性(是由該節點樣本占總體樣本*gini的減少量) importances = list(model_tree.feature_importances_) print(importances)#輸出變量重要的前幾個變量(求最大的三個索引nsmallest與nlargest相反求最小) import heapq imp_index = list(map(importances.index, heapq.nlargest(3,importances))) var_imp = [] for i in imp_index:var_imp.append(list1[i]) print(var_imp)5.4 決策樹以圖的形式輸出
#解決中文亂碼問題(含中文的輸出方式) from sklearn.externals.six import StringIO import pydotplus from IPython.display import Image dot_data = StringIO() #決策樹圖 list1 = ['var1','var2','var3','var4','var5','var6'] tree.export_graphviz(model_tree, out_file=dot_data, feature_names=list1,filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data.getvalue().replace( 'helvetica' ,' "Microsoft YaHei" ')) graph.write_png("result1.png")#將圖畫出來 #https://blog.csdn.net/qq_39386012/article/details/83857609#commentBox Image(graph.create_png())#在jupter中可視化出來from sklearn import tree import pydotplus #決策樹圖(不含含中文的輸出方式) list1 = ['var1','var2','var3','var4','var5','var6'] dot_data = tree.export_graphviz(model_tree, out_file=None, feature_names=list1,filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data) graph.write_png("result2.png")#將圖畫出來決策樹參數詳解
| criterion | 默認值:gini,即CART算法 輸入:entropy, gini | 特征選擇標準 |
| splitter | 默認值:best 輸入:best, random | best在特征的所有劃分點中找出最優的劃分點,random隨機的在部分劃分點中找 局部最優的劃分點。默認的‘best’適合樣本量不大的時候,而如果樣本數據量非常大,此時決策樹構建推薦‘random’ |
| max_depth | 默認值:None 輸入:int, None | 決策樹最大深度。一般數據比較少或者特征少的時候可以不用管這個值,如果模型樣本數量多,特征也多時,推薦限制這個最大深度,具體取值取決于數據的分布。常用的可以取值10-100之間,常用來解決過擬合 |
| min_samples_split | 默認值:2 輸入:int, float | 內部節點(即判斷條件)再劃分所需最小樣本數。如果是int,則取傳入值本身作為最小樣本數;如果是float,則取ceil(min_samples_split*樣本數量)作為最小樣本數。(向上取整) |
| min_samples_leaf | 輸入:int, float | 葉子節點(即分類)最少樣本數。如果是int,則取傳入值本身作為最小樣本數;如果是float,則取ceil(min_samples_leaf*樣本數量)的值作為最小樣本數。這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小于樣本數,則會和兄弟節點一起被剪枝 |
| min_weight_fraction_leaf | 默認值:0 輸入:float | 葉子節點(即分類)最小的樣本權重和,【float】。這個值限制了葉子節點所有樣本權重和的最小值,如果小于這個值,則會和兄弟節點一起被剪枝。默認是0,就是不考慮權重問題,所有樣本的權重相同。 注:一般來說如果我們有較多樣本有缺失值或者分類樹樣本的分布類別偏差很大,就會引入樣本權重,這時就要注意此值 |
| max_features | 輸入:int,float | 在劃分數據集時考慮的最多的特征值數量,【int值】。在每次split時最大特征數;【float值】表示百分數,即(max_features*n_features) |
| random_state | 默認值:None 輸入:int, randomSate instance, None | |
| max_leaf_nodes | 默認值:None 輸入:int, None | 最大葉子節點數。通過設置最大葉子節點數,可以防止過擬合。默認值None,默認情況下不設置最大葉子節點數。如果加了限制,算法會建立在最大葉子節點數內最優的決策樹。如果特征不多,可以不考慮這個值,但是如果特征多,可以加限制,具體的值可以通過交叉驗證得到 |
| min_impurity_decrease | 默認值:0 輸入:float | 節點劃分最小不純度,默認值為‘0’。限制決策樹的增長,節點的不純度(基尼系數,信息增益,均方差,絕對差)必須大于這個閾值,否則該節點不再生成子節點 |
| class_weight | 默認值:None 輸入:dict, list of dicts, balanced | 類別權重(不適用于回歸樹,sklearn.tree.DecisionTreeRegressor) 指定樣本各類別的權重,主要是為了防止訓練集某些類別的樣本過多,導致訓練的決策樹過于偏向這些類別。balanced,算法自己計算權重,樣本量少的類別所對應的樣本權重會更高。如果樣本類別分布沒有明顯的偏倚,則可以不管這個參數 |
| presort | 默認值:False 輸入:bool | 表示在進行擬合之前,是否預分數據來加快樹的構建 注:對于數據集非常龐大的分類,presort=true將導致整個分類變得緩慢;當數據集較小,且樹的深度有限制,presort=true才會加速分類 |
決策樹調參注意事項
- 當樣本少數量但是樣本特征非常多的時候,決策樹很容易過擬合,一般來說,樣本數比特征數多一些會比較容易建立健壯的模型
- 如果樣本數量少但是樣本特征非常多,在擬合決策樹模型前,推薦先做維度規約,比如主成分分析(PCA),特征選擇(Losso)或者獨立成分分析(ICA)。這樣特征的維度會大大減小。再來擬合決策樹模型效果會好。
- 推薦多用決策樹的可視化,同時先限制決策樹的深度(比如最多3層),這樣可以先觀察下生成的決策樹里數據的初步擬合情況,然后再決定是否要增加深度。
- 在訓練模型先,注意觀察樣本的類別情況(主要指分類樹),如果類別分布非常不均勻,就要考慮用class_weight來限制模型過于偏向樣本多的類別。
- 決策樹的數組使用的是numpy的float32類型,如果訓練數據不是這樣的格式,算法會先做copy再運行。
- 如果輸入的樣本矩陣是稀疏的,推薦在擬合前調用csc_matrix稀疏化,在預測前調用csr_matrix稀疏化。
總結
以上是生活随笔為你收集整理的决策树原理详解及python代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习算法—集成算法原理详解
- 下一篇: GBDT(回归树)原理详解与python