决策树原理详解及python代码实现
決策樹(shù)算法(信貸中常用來(lái)尋找規(guī)則)
- 1、算法原理
- 1.1 ID3(多叉樹(shù)分類(lèi))
- 1.2 C4.5(多叉樹(shù)分類(lèi))
- 1.3 Cart(二叉樹(shù)分類(lèi)+回歸)
- 2、ID3、C4.5與Cart比較
- 3、算法優(yōu)缺點(diǎn)
- 4、算法需要注意的點(diǎn)
- 5、python代碼實(shí)現(xiàn)
- 5.1導(dǎo)入相關(guān)包
- 5.2 讀取數(shù)據(jù)并數(shù)據(jù)處理
- 5.3 模型訓(xùn)練
- 5.4 評(píng)估指標(biāo)
- 5.4 決策樹(shù)以圖的形式輸出
1、算法原理
1.1 ID3(多叉樹(shù)分類(lèi))
信息熵:Ent(D)=?∑i=1npilogpiEnt(D)=-\sum_{i=1}^np_ilogp_iEnt(D)=?∑i=1n?pi?logpi?其中n為類(lèi)別,pip_ipi?為每個(gè)類(lèi)別的概率,DDD為某個(gè)特征,越小越確定
信息增益: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個(gè)樣本,9個(gè)1和6個(gè)0;有個(gè)特征A(取值A1A_1A1?、A2A_2A2?、A3A_3A3?,其中A1A_1A1?(3個(gè)1,2個(gè)0),其中A2A_2A2?(2個(gè)1,3個(gè)0)其中A3A_3A3?(4個(gè)1,1個(gè)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個(gè)值為12\frac{1}{2}21?,3個(gè)值為13\frac{1}{3}31?,但是3個(gè)信息增益會(huì)更大)
- ID3沒(méi)有考慮連續(xù)特征
- ID3對(duì)缺失值未考慮
需要懲罰取值較多的信息增益,引出了信息增益率,即C4.5的算法
1.2 C4.5(多叉樹(shù)分類(lèi))
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)
- 如果為連續(xù)型變量,先從大到小排序,分別取2個(gè)中值(均值)作為劃分點(diǎn)計(jì)算
引出了分類(lèi)+回歸的決策樹(shù)
1.3 Cart(二叉樹(shù)分類(lèi)+回歸)
Gini(D)=1?∑i=1npi2Gini(D)=1-\sum_{i=1}^np_i^2Gini(D)=1?∑i=1n?pi2? 反映隨機(jī)抽2個(gè)樣本,不一致的概率,越小越好(越純)
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
如果為連續(xù)性變量處理方式與C4.5相同
回歸mse:
- 根據(jù)每一個(gè)連續(xù)值作為劃分點(diǎn)(或用分類(lèi)的方式取均值作為劃分點(diǎn)),將其劃分S1S_1S1?、S2S_2S2?
- 計(jì)算每個(gè)分支(S1S_1S1?、S2S_2S2?)的均值。 mean=sum(s1或s2里真實(shí)值)該集合樣本總數(shù)mean=\frac{sum(s_1或s_2里真實(shí)值)}{該集合樣本總數(shù)}mean=該集合樣本總數(shù)sum(s1?或s2?里真實(shí)值)?即為該分支的預(yù)測(cè)值
- 計(jì)算S1S_1S1?、S2S_2S2?的mse的和。 mse=(該集合每一個(gè)樣本真實(shí)值?mean)2mse=(該集合每一個(gè)樣本真實(shí)值-mean)^2mse=(該集合每一個(gè)樣本真實(shí)值?mean)2
注:實(shí)踐證明GiniGiniGini和GainGainGain效果差不多
2、ID3、C4.5與Cart比較
| 連續(xù)值處理 | ×\times× | √\surd√ | √\surd√ |
| 缺失值處理 | ×\times× | √\surd√ | √\surd√ |
| 剪枝 | ×\times× | √\surd√ | √\surd√ |
- ID3、C4.5與Cart特征選擇只選一個(gè)特征。但大多數(shù)由一組特征決定。這樣得到的決策樹(shù)更準(zhǔn)確(oc1)
- 樣本發(fā)生一點(diǎn)改變,樹(shù)的結(jié)構(gòu)可能會(huì)發(fā)生劇烈的變化
3、算法優(yōu)缺點(diǎn)
一、優(yōu)點(diǎn):
- 簡(jiǎn)單直觀,生成的決策樹(shù)可解釋性強(qiáng)
- 不需要數(shù)據(jù)預(yù)處理(例如歸一化處理,但封裝的scikit-learn需要處理缺失值與字符型變量)
- 可以處理多維度多分類(lèi)問(wèn)題
一、缺點(diǎn):
- 容易過(guò)擬合
- 樣本發(fā)生改變可能導(dǎo)致完全不同的樹(shù)
- 樣本不平衡時(shí),樹(shù)會(huì)偏向于類(lèi)別較多的一類(lèi)
4、算法需要注意的點(diǎn)
決策樹(shù)的構(gòu)建過(guò)程中出現(xiàn)過(guò)擬合的原因及解決方法
原因:
- 在構(gòu)建過(guò)程中沒(méi)有進(jìn)行合理的限制(如樹(shù)的深度等)
- 樣本中有噪聲數(shù)據(jù),沒(méi)有進(jìn)行有效的剔除
- 變量較多也容易產(chǎn)生過(guò)擬合
解決方法: 剪枝、限制深度、RF、正則化等
決策樹(shù)如何處理缺失值
1、使用權(quán)重方法重構(gòu)。(可認(rèn)為以前1?Gain*Gain?Gain,現(xiàn)在無(wú)缺失比率?Gain*Gain?Gain)訓(xùn)練時(shí)特征出現(xiàn)缺失怎么處理(劃分)即不考慮缺失,然后重賦權(quán)重
2、將缺失(劃分變量)的樣本中分別放到不同分支再進(jìn)行分支。缺失變量樣本的歸屬分支問(wèn)題
3、同時(shí)探查所有分支,然后算每個(gè)類(lèi)別的概率,取概率最大的類(lèi)別賦值該樣本。測(cè)試集中缺失處理
決策樹(shù)遞歸終止的條件
1、所有子集被正確分類(lèi);2、沒(méi)有合適的特征選擇或信息增益(信息增益率/Gini)很小
決策樹(shù)的變量重要性
如樣本分裂占比?*?Gini/信息增益比
5、python代碼實(shí)現(xiàn)
5.1導(dǎo)入相關(guān)包
import numpy as np import pandas as pd from sklearn.preprocessing import LabelEncoder #分類(lèi)變量編碼包 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/'#決策樹(shù)可視化的包5.2 讀取數(shù)據(jù)并數(shù)據(jù)處理
data = pd.read_excel('ceshi.xlsx',sheet_name = 'Sheet2') #分類(lèi)變量編碼 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)) #在單變量分析的基礎(chǔ)上填充缺失值(看哪一組的1的比率最接近于缺失值的那一組) data['var1'] = data['var1'].fillna(0.42089) data['var2'] = data['var2'].fillna(125.854) #劃分?jǐn)?shù)據(jù)集 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 模型訓(xùn)練
#建立模型(min_samples_leaf和min_samples_split需要慎重選擇)(和傳統(tǒng)決策樹(shù)有很大區(qū)別) model_tree = DecisionTreeClassifier(criterion='gini',#劃分標(biāo)準(zhǔn)splitter='best',#特征劃分標(biāo)準(zhǔn)max_depth=3,#樹(shù)的最大深度min_samples_split=20,#劃分所需要的最小樣本數(shù)min_samples_leaf=10,#分到每個(gè)葉子最小樣本數(shù)max_features=None,#用于參與劃分的變量個(gè)數(shù) max_leaf_nodes=None,#最大葉子節(jié)點(diǎn)數(shù) min_impurity_decrease=0.0,#節(jié)點(diǎn)劃分最小不純度 min_weight_fraction_leaf=0.0,#葉子節(jié)點(diǎn)最小的樣本權(quán)重和presort=False,#進(jìn)行擬合前是否預(yù)分?jǐn)?shù)據(jù)來(lái)加快樹(shù)的構(gòu)建random_state=None, )#建模要class_weight='balanced' model_tree.fit(x_train, y_train)5.4 評(píng)估指標(biāo)
test_proba = pd.DataFrame(model_tree.predict_proba(x_test))[1].values#預(yù)測(cè)為0的概率 print('測(cè)試集AUC: %.4f'%roc_auc_score(y_test,test_proba))#AUC,預(yù)測(cè)為概率#變量重要性(是由該節(jié)點(diǎn)樣本占總體樣本*gini的減少量) importances = list(model_tree.feature_importances_) print(importances)#輸出變量重要的前幾個(gè)變量(求最大的三個(gè)索引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 決策樹(shù)以圖的形式輸出
#解決中文亂碼問(wèn)題(含中文的輸出方式) from sklearn.externals.six import StringIO import pydotplus from IPython.display import Image dot_data = StringIO() #決策樹(shù)圖 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")#將圖畫(huà)出來(lái) #https://blog.csdn.net/qq_39386012/article/details/83857609#commentBox Image(graph.create_png())#在jupter中可視化出來(lái)from sklearn import tree import pydotplus #決策樹(shù)圖(不含含中文的輸出方式) 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")#將圖畫(huà)出來(lái)決策樹(shù)參數(shù)詳解
| criterion | 默認(rèn)值:gini,即CART算法 輸入:entropy, gini | 特征選擇標(biāo)準(zhǔn) |
| splitter | 默認(rèn)值:best 輸入:best, random | best在特征的所有劃分點(diǎn)中找出最優(yōu)的劃分點(diǎn),random隨機(jī)的在部分劃分點(diǎn)中找 局部最優(yōu)的劃分點(diǎn)。默認(rèn)的‘best’適合樣本量不大的時(shí)候,而如果樣本數(shù)據(jù)量非常大,此時(shí)決策樹(shù)構(gòu)建推薦‘random’ |
| max_depth | 默認(rèn)值:None 輸入:int, None | 決策樹(shù)最大深度。一般數(shù)據(jù)比較少或者特征少的時(shí)候可以不用管這個(gè)值,如果模型樣本數(shù)量多,特征也多時(shí),推薦限制這個(gè)最大深度,具體取值取決于數(shù)據(jù)的分布。常用的可以取值10-100之間,常用來(lái)解決過(guò)擬合 |
| min_samples_split | 默認(rèn)值:2 輸入:int, float | 內(nèi)部節(jié)點(diǎn)(即判斷條件)再劃分所需最小樣本數(shù)。如果是int,則取傳入值本身作為最小樣本數(shù);如果是float,則取ceil(min_samples_split*樣本數(shù)量)作為最小樣本數(shù)。(向上取整) |
| min_samples_leaf | 輸入:int, float | 葉子節(jié)點(diǎn)(即分類(lèi))最少樣本數(shù)。如果是int,則取傳入值本身作為最小樣本數(shù);如果是float,則取ceil(min_samples_leaf*樣本數(shù)量)的值作為最小樣本數(shù)。這個(gè)值限制了葉子節(jié)點(diǎn)最少的樣本數(shù),如果某葉子節(jié)點(diǎn)數(shù)目小于樣本數(shù),則會(huì)和兄弟節(jié)點(diǎn)一起被剪枝 |
| min_weight_fraction_leaf | 默認(rèn)值:0 輸入:float | 葉子節(jié)點(diǎn)(即分類(lèi))最小的樣本權(quán)重和,【float】。這個(gè)值限制了葉子節(jié)點(diǎn)所有樣本權(quán)重和的最小值,如果小于這個(gè)值,則會(huì)和兄弟節(jié)點(diǎn)一起被剪枝。默認(rèn)是0,就是不考慮權(quán)重問(wèn)題,所有樣本的權(quán)重相同。 注:一般來(lái)說(shuō)如果我們有較多樣本有缺失值或者分類(lèi)樹(shù)樣本的分布類(lèi)別偏差很大,就會(huì)引入樣本權(quán)重,這時(shí)就要注意此值 |
| max_features | 輸入:int,float | 在劃分?jǐn)?shù)據(jù)集時(shí)考慮的最多的特征值數(shù)量,【int值】。在每次split時(shí)最大特征數(shù);【float值】表示百分?jǐn)?shù),即(max_features*n_features) |
| random_state | 默認(rèn)值:None 輸入:int, randomSate instance, None | |
| max_leaf_nodes | 默認(rèn)值:None 輸入:int, None | 最大葉子節(jié)點(diǎn)數(shù)。通過(guò)設(shè)置最大葉子節(jié)點(diǎn)數(shù),可以防止過(guò)擬合。默認(rèn)值None,默認(rèn)情況下不設(shè)置最大葉子節(jié)點(diǎn)數(shù)。如果加了限制,算法會(huì)建立在最大葉子節(jié)點(diǎn)數(shù)內(nèi)最優(yōu)的決策樹(shù)。如果特征不多,可以不考慮這個(gè)值,但是如果特征多,可以加限制,具體的值可以通過(guò)交叉驗(yàn)證得到 |
| min_impurity_decrease | 默認(rèn)值:0 輸入:float | 節(jié)點(diǎn)劃分最小不純度,默認(rèn)值為‘0’。限制決策樹(shù)的增長(zhǎng),節(jié)點(diǎn)的不純度(基尼系數(shù),信息增益,均方差,絕對(duì)差)必須大于這個(gè)閾值,否則該節(jié)點(diǎn)不再生成子節(jié)點(diǎn) |
| class_weight | 默認(rèn)值:None 輸入:dict, list of dicts, balanced | 類(lèi)別權(quán)重(不適用于回歸樹(shù),sklearn.tree.DecisionTreeRegressor) 指定樣本各類(lèi)別的權(quán)重,主要是為了防止訓(xùn)練集某些類(lèi)別的樣本過(guò)多,導(dǎo)致訓(xùn)練的決策樹(shù)過(guò)于偏向這些類(lèi)別。balanced,算法自己計(jì)算權(quán)重,樣本量少的類(lèi)別所對(duì)應(yīng)的樣本權(quán)重會(huì)更高。如果樣本類(lèi)別分布沒(méi)有明顯的偏倚,則可以不管這個(gè)參數(shù) |
| presort | 默認(rèn)值:False 輸入:bool | 表示在進(jìn)行擬合之前,是否預(yù)分?jǐn)?shù)據(jù)來(lái)加快樹(shù)的構(gòu)建 注:對(duì)于數(shù)據(jù)集非常龐大的分類(lèi),presort=true將導(dǎo)致整個(gè)分類(lèi)變得緩慢;當(dāng)數(shù)據(jù)集較小,且樹(shù)的深度有限制,presort=true才會(huì)加速分類(lèi) |
決策樹(shù)調(diào)參注意事項(xiàng)
- 當(dāng)樣本少數(shù)量但是樣本特征非常多的時(shí)候,決策樹(shù)很容易過(guò)擬合,一般來(lái)說(shuō),樣本數(shù)比特征數(shù)多一些會(huì)比較容易建立健壯的模型
- 如果樣本數(shù)量少但是樣本特征非常多,在擬合決策樹(shù)模型前,推薦先做維度規(guī)約,比如主成分分析(PCA),特征選擇(Losso)或者獨(dú)立成分分析(ICA)。這樣特征的維度會(huì)大大減小。再來(lái)擬合決策樹(shù)模型效果會(huì)好。
- 推薦多用決策樹(shù)的可視化,同時(shí)先限制決策樹(shù)的深度(比如最多3層),這樣可以先觀察下生成的決策樹(shù)里數(shù)據(jù)的初步擬合情況,然后再?zèng)Q定是否要增加深度。
- 在訓(xùn)練模型先,注意觀察樣本的類(lèi)別情況(主要指分類(lèi)樹(shù)),如果類(lèi)別分布非常不均勻,就要考慮用class_weight來(lái)限制模型過(guò)于偏向樣本多的類(lèi)別。
- 決策樹(shù)的數(shù)組使用的是numpy的float32類(lèi)型,如果訓(xùn)練數(shù)據(jù)不是這樣的格式,算法會(huì)先做copy再運(yùn)行。
- 如果輸入的樣本矩陣是稀疏的,推薦在擬合前調(diào)用csc_matrix稀疏化,在預(yù)測(cè)前調(diào)用csr_matrix稀疏化。
總結(jié)
以上是生活随笔為你收集整理的决策树原理详解及python代码实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 机器学习算法—集成算法原理详解
- 下一篇: GBDT(回归树)原理详解与python