決策樹
優點:
- - 計算復雜度不高,易於理解和解釋,甚至比線性回歸更直觀;
- - 與人類做決策思考的思維習慣契合;
- - 模型可以通過樹的形式進行可視化展示;
- - 可以直接處理非數值型數據,不需要進行啞變量的轉化,甚至可以直接處理含缺失值的數據;
- - 可以處理不相關特征數據。
缺點:
- - 對於有大量數值型輸入和輸出的問題,特別是當數值型變量之間存在許多錯綜復雜的關系,如金融數據分析,決策樹未必是一個好的選擇;
- - 決定分類的因素更傾向於更多變量的復雜組合;
- - 模型不夠穩健,某一個節點的小小變化可能導致整個樹會有很大的不同。
- - 可能會產生過度匹配(過擬合)問題。
使用數據類型:數值型和離散型(標稱型)。
工作原理:
決策樹算法通常是一個遞歸的選擇最優特征的過程,並根據該特征對訓練數據進行分割,使得對各個子數據集有一個最好的分類過程。這一過程對應着特征空間的划分,也對應着決策樹的構建。開始,構建根結點,將所有訓練數據都放在根結點。選擇一個最優特征,按照這一特征將訓練數據集分割成子集,使得各個子集有一個在當前條件下最好的分類。如果這些子集已經能夠被基本正確分類,那么構建葉節點,並將這些子集分到所對應的葉節點中去;如果還有子集不能被基本正確分類,那么就對這些子集選擇新的最優特征,繼續對其進行分割,構建相應的節點。如此遞歸的進行下去,直到所有的訓練數據子集被基本正確分類,或者沒有合適的特征為止。最后每個子集都被分到葉節點上,即都有了明確的類,這就生成了一顆決策樹。
決策樹可以看作if-then規則的集合,也可以認為是定義在特征空間與類空間上的條件概率分布。
將決策樹轉換成if-then規則的過程如下:
- 由決策樹的根節點到葉節點的每一條路徑構建一條規則;
- 路徑內部結點的特征對應規則的條件;
- 葉節點的類對應規則的結論.
決策樹的路徑具有一個重要的性質:互斥且完備,即每一個樣本均被且只能被一條路徑所覆蓋。
決策樹由結點和有向邊組成。結點有兩種類型: 內部結點和葉節點。內部節點表示一個特征或屬性,葉節點表示一個類。
決策樹通常有三個步驟:特征選擇、決策樹生成、決策樹的修剪。
特征選擇
如果利用一個特征進行分類的結果與隨機分類的結果無異,則可以認為這個特征是不具備分類能力的。而我們應該基於什么准則來判定一個特征的分類能力呢?這時候,需要引入一個概念:信息增益。特征選擇原則:對訓練數據集,計算其每個特征的信息增益,並比它們的大小,從而選擇信息增益最大的特征。
以信息增益作為特征選擇准則,會存在偏向於選擇取值較多的特征的問題。可以采用信息增益比對這一問題進行校正。原則也是選擇信息增益比最大的特征。
決策樹的生成
決策樹的生成算法有很多變形,這里介紹幾種經典的實現算法:ID3算法,C4.5算法和CART算法。這些算法的主要區別在於分類結點上特征選擇的選取標准不同。下面詳細了解一下算法的具體實現過程。
ID3算法
ID3算法的核心是在決策樹的各個結點上應用信息增益准則進行特征選擇。具體做法是:
-
- 從根節點開始,對結點計算所有可能特征的信息增益,選擇信息增益最大的特征作為結點的特征,並由該特征的不同取值構建子節點;
- 對子節點遞歸地調用以上方法,構建決策樹;
- 直到所有特征的信息增益均很小或者沒有特征可選時為止。
C4.5算法(是ID3的升級,考慮自身熵值)
C4.5算法與ID3算法的區別主要在於它在生產決策樹的過程中,使用信息增益比來進行特征選擇。
CART算法
分類與回歸樹(classification and regression tree,CART)與C4.5算法一樣,由ID3算法演化而來。CART假設決策樹是一個二叉樹,它通過遞歸地二分每個特征,將特征空間划分為有限個單元,並在這些單元上確定預測的概率分布。CART算法中,對於回歸樹(數值型),采用的是平方誤差最小化准則;對於分類樹(離散型),采用基尼指數最小化准則。
決策樹的剪枝
如果對訓練集建立完整的決策樹,會使得模型過於針對訓練數據,擬合了大部分的噪聲,即出現過度擬合的現象。為了避免這個問題,有兩種解決的辦法:
- 當熵減少的數量小於某一個閾值時,就停止分支的創建。這是一種貪心算法。
- 先創建完整的決策樹,然后再嘗試消除多余的節點,也就是采用減枝的方法。
方法1存在一個潛在的問題:有可能某一次分支的創建不會令熵有太大的下降,但是隨后的子分支卻有可能會使得熵大幅降低。因此,我們更傾向於采用剪枝的方法。
剪枝策略:
-
- 預剪枝(實用):邊建立決策樹邊進行剪枝操作。方法:限制樹的深度,葉子節點的個數,葉子節點包含的樣本樹,信息增益量等。
- 后剪枝:當建立完決策樹后來進行剪枝操作。
DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,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')
函數為創建一個決策樹模型,其函數的參數含義如下所示:
- criterion:gini或者entropy,前者是基尼系數,后者是信息熵。
- splitter: best or random 前者是在所有特征中找最好的切分點 后者是在部分特征中,默認的”best”適合樣本量不大的時候,而如果樣本數據量非常大,此時決策樹構建推薦”random” 。
- max_features:None(所有),log2,sqrt,N 特征小於50的時候一般使用所有的
- max_depth: int or None, optional (default=None) 設置決策隨機森林中的決策樹的最大深度,深度越大,越容易過擬合,推薦樹的深度為:5-20之間。
- min_samples_split:設置結點的最小樣本數量,當樣本數量可能小於此值時,結點將不會在划分。
- min_samples_leaf: 這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。
- min_weight_fraction_leaf: 這個值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝默認是0,就是不考慮權重問題。
- max_leaf_nodes: 通過限制最大葉子節點數,可以防止過擬合,默認是"None”,即不限制最大的葉子節點數。
- class_weight: 指定樣本各類別的的權重,主要是為了防止訓練集某些類別的樣本過多導致訓練的決策樹過於偏向這些類別。這里可以自己指定各個樣本的權重,如果使用“balanced”,則算法會自己計算權重,樣本量少的類別所對應的樣本權重會高。
- min_impurity_split: 這個值限制了決策樹的增長,如果某節點的不純度(基尼系數,信息增益,均方差,絕對差)小於這個閾值則該節點不再生成子節點。即為葉子節點 。
#導入 tree 模塊 from sklearn import tree #導入紅酒數據集,數據集包含來自3種不同起源的葡萄酒的共178條記錄。 #13個屬性是葡萄酒的13種化學成分。通過化學分析可以來推斷葡萄酒的起源。起源為三個產地 #值得一提的是所有屬性變量都是連續變量 from sklearn.datasets import load_wine #導入訓練集和測試集切分包 from sklearn.model_selection import train_test_split import pandas as pd #import pydotplus #紅酒數據集的數據探索 wine = load_wine() #print(wine) #print(wine.data) #178*13 print('x數據集形狀:',wine.data.shape) #print(wine.target) #178*1 print('y數據集形狀:',wine.target.shape) #將x,y都放到數據集data_frame中 data_frame = pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1) #顯示前10行 print('數據前十行顯示:\n',data_frame.head(10)) #顯示數據集特征列名 print('數據集特征列名:',wine.feature_names) #顯示數據集的標簽分類 print('數據集標簽分類:',wine.target_names) #70%為訓練數據,30%為測試數據 Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3) print('訓練數據的大小為:',Xtrain.shape) print('測試數據的大小為:',Xtest.shape) #初始化樹模型,criterion:gini或者entropy,前者是基尼系數,后者是信息熵。 clf = tree.DecisionTreeClassifier(criterion="entropy") #實例化訓練集 clf = clf.fit(Xtrain, Ytrain) #返回測試集的准確度 score = clf.score(Xtest, Ytest) y = clf.predict(Xtest) print('測試集的准確度:',score) for each in range(len(Ytest)): print('預測結果:',y[each],'\t真實結果:',Ytest[each],'\n') #特征重要性 feature_name = ['酒精','蘋果酸','灰','灰的鹼性','鎂','總酚','類黃酮','非黃烷類酚類',\ '花青素','顏色強度','色調','od280/od315 稀釋葡萄酒','脯氨酸'] print(clf.feature_importances_) print([*zip(feature_name,clf.feature_importances_)]) #生成一顆決策樹,該部分未成功 #import graphviz #dot_data = StringIO() #tree.export_graphviz(clf # ,out_file=None # ,feature_names= feature_name # ,class_names=["琴酒","雪莉","貝爾摩德"] # ,filled=True # ,rounded=True # ) #graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) #graph.write_pdf("F://python入門//文件//wine.pdf")
結果
x數據集形狀: (178, 13) y數據集形狀: (178,) 數據前十行顯示: 0 1 2 3 4 5 ... 8 9 10 11 12 0 0 14.23 1.71 2.43 15.6 127.0 2.80 ... 2.29 5.64 1.04 3.92 1065.0 0 1 13.20 1.78 2.14 11.2 100.0 2.65 ... 1.28 4.38 1.05 3.40 1050.0 0 2 13.16 2.36 2.67 18.6 101.0 2.80 ... 2.81 5.68 1.03 3.17 1185.0 0 3 14.37 1.95 2.50 16.8 113.0 3.85 ... 2.18 7.80 0.86 3.45 1480.0 0 4 13.24 2.59 2.87 21.0 118.0 2.80 ... 1.82 4.32 1.04 2.93 735.0 0 5 14.20 1.76 2.45 15.2 112.0 3.27 ... 1.97 6.75 1.05 2.85 1450.0 0 6 14.39 1.87 2.45 14.6 96.0 2.50 ... 1.98 5.25 1.02 3.58 1290.0 0 7 14.06 2.15 2.61 17.6 121.0 2.60 ... 1.25 5.05 1.06 3.58 1295.0 0 8 14.83 1.64 2.17 14.0 97.0 2.80 ... 1.98 5.20 1.08 2.85 1045.0 0 9 13.86 1.35 2.27 16.0 98.0 2.98 ... 1.85 7.22 1.01 3.55 1045.0 0 [10 rows x 14 columns] 數據集特征列名: ['alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols', 'proanthocyanins', 'color_intensity', 'hue', 'od280/od315_of_diluted_wines', 'proline'] 數據集標簽分類: ['class_0' 'class_1' 'class_2'] 訓練數據的大小為: (124, 13) 測試數據的大小為: (54, 13) 測試集的准確度: 0.9074074074074074 預測結果: 0 真實結果: 0 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 0 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 0 真實結果: 0 預測結果: 0 真實結果: 0 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 2 真實結果: 2 預測結果: 0 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 0 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 0 真實結果: 0 預測結果: 2 真實結果: 2 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 1 真實結果: 1 預測結果: 1 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 2 真實結果: 2 預測結果: 0 真實結果: 0 預測結果: 2 真實結果: 2 預測結果: 2 真實結果: 2 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 預測結果: 1 真實結果: 1 預測結果: 0 真實結果: 0 預測結果: 0 真實結果: 0 預測結果: 2 真實結果: 2 預測結果: 2 真實結果: 2 預測結果: 1 真實結果: 1 [0. 0.02120488 0. 0. 0. 0. 0.41936238 0. 0. 0.14980257 0.0354628 0. 0.37416737] [('酒精', 0.0), ('蘋果酸', 0.021204876662634046), ('灰', 0.0), ('灰的鹼性', 0.0), ('鎂', 0.0), ('總酚', 0.0), ('類黃酮', 0.41936238395073366), ('非黃烷類酚類', 0.0), ('花青素', 0.0), ('顏色強度', 0.14980257279491835), ('色調', 0.03546279572288287), ('od280/od315 稀釋葡萄酒', 0.0), ('脯氨酸', 0.37416737086883106)]
以上程序運行過程中會報錯:ModuleNotFoundError: No module named 'pydotplus'
第一步:打開Anaconda Prompt,上直接pip install pydotplus,安裝即可