目錄
主要是分享決策的基本知識點,重點在分類決策樹上,對於迴歸的決策樹後面在給出。希望大家和我一起做知識的傳播者啦!😄 😃 😁 😮
決策樹
英文名字:Descision Tree
什麼是決策樹
舉個校園相親的例子,今天校園的小貓(女)和小狗(男)準備配對,小貓如何才能在衆多的優質🐶的心儀的狗呢?於是呢?有一隻特乖巧的小貓找到了你,你正在學習機器學習,剛好學習了決策樹,準備給這隻貓貓挑選優質狗,當然,你不僅僅是直接告訴貓哪些狗是合適你的?你更應該詳細的給貓講解決策樹是如何根據它提出的標準選出的符合要求的狗呢?
貓給出如下信息:
年齡<0.5 不心儀;年齡大於>=0.5 6.5<=體重<=8.5;心儀; 年齡>=0.5 體重>8.5 長相好 心儀;其餘情況不心儀; 根據上述條件可以構造一顆樹:
上面的圖就是決策樹,最終的結果是心儀或者不心儀。決策樹算法以樹形結構表示數據分類的結果
基本概念
決策樹屬於也只能非參數學習算法、可以用於解決(多)分類問題,迴歸問題。 迴歸問題的結果,葉子結點的平均值是迴歸問題的解。
根節點:決策樹具有數據結構裏面的二叉樹、樹的全部屬性
非葉子節點 :(決策點) 代表測試的條件,數據的屬性的測試
葉子節點 :分類後獲得分類標記
分支: 測試的結果
數學問題-熵-Gini係數
什麼是熵:熵的概念源於物理學,用於度量一個熱力學系統的無序程度。
信息熵:不得不提香農這個大寫的人啦!信息論裏面的知識。在信息論裏面,信息熵衡量信息量的大小,也就是對隨機變量不確定度的一個衡量。熵越大,不確定性越大;
對於某個單符號無記憶信源,發出符號(\(x_i\))的概率是\(p_i\),概率越大,符號的信息量就越小,香農公式 \(I(x_i)=-log_{p_i}\)。信源所含的信息熵就是信息量的期望]
\(H(x)=-\sum p_i*log_{p_i}\)
Gini係數: \(Gimi(p) = 1-\sum_{k=1}^{K}p_k^2\)
決策樹如何構建的問題
自我提問階段:
每個節點的位置如何確定?
答:每次選入的屬性,進行劃分,都是使得決策樹在這個節點的根據你自己選擇的標準(信息熵最小、信息增益最大、gini係數最小).
每個節點在哪個值上做劃分,確定分支結構呢?
遍歷劃分的節點的分界值操作
訓練算法
基於信息熵的構造
當選擇某個節點時,我們就希望這個節點的信息熵越小越好,那麼不確定性越小。
\[ H(x) = -p_i(x)log^{p_i(x)}
= -\frac{n_j}{S}log^{\frac{n_j}{S}}\]
\(n_j\): 第j個類別,在樣本中出現的頻數
\(S\): 樣本個數
對於離散屬性,直接計算信息熵,連續屬性,就需要劃分區間,按區間計算信息熵。
- 基於某一層的數據集 a. 遍歷計算所有屬性,遍歷相應屬性以不同值爲分截點的信息熵 b. 選擇信息熵最小的作爲節點
如果到達終止條件,返回相應信息,否則,按照分支重複步驟1
ID3算法: 信息增益最大化
C:類別
\[H(C)=-\sum_{i=1}^{m}p_i log _2^{p_i}\]
按照D組劃分C
\[H(C/D)=\sum_{i=1}^{v}\frac{|C_i|}{|C|}H(C_i)\]
信息增益
\[ gain(D) = gain(C)-H(C/D)\]
這裏我就以網上給出的數據爲例,給出根據信息熵構成決策樹的計算過程。
- 確定特徵,統計屬性值和分解結果,總共四個特徵,四種特徵的統計結果如下圖:
- 根據歷史數據,在不知到任何情況下,計算數據本身的熵爲
\[ - \frac{9}{14}log_2 \frac{9}{14}-\frac{5}{14}log_2\frac{5}{14}=0.940\] 計算每個特徵做爲節點的信息熵
以天氣爲例,天氣三種屬性,當Outlook = sunny時,H(x) = \(-\frac{2}{5}log_2\frac{2}{5}-\frac{3}{5}log_2\frac{3}{5}\); 當Outlook= overcast,\(H(x)=0\),當Outlook = rainy ,\(H(x) = 0.971\)
所以,當選天氣作爲節點時,此時\(H(x)=\frac{5}{14}*0.971+\frac{4}{14}*0+\frac{5}{14}*0.971 = 0.693\),gain(天氣) = 0.247
同理,
gain(溫度) =0.029 gain(溼度)=0.152 gain(風)=0.048
因此選擇天氣節點,在遞歸實現其他節點的選擇。C4.5: 信息增益率
如果這裏考慮了一列ID,每個ID出現一次,所以算出的信息增益大。
$ H(x) = 0$,信息增益最大化了,可以引入信息增益率
\[C(T) = \frac{信息增益}{H(T)} =\frac{H(C)-H(C/T)}{H(T)}\]CART:基尼(Gini)係數
\[G = 1-\sum_{i=l_k}^{k}p_i^2\],也是對隨機變量不確定性的一個衡量,gini越大,不確定性越大
連續屬性的處理方法
選取分解點的問題: 分成不同的區間(二分、三分....),分別計算增益值,然後比較選擇。
評價
評價函數:
\[C(T) = \sum_{releaf} N_t*H(T)\]
$ N_t$:每個葉子節點裏面含有的樣本個數
\(H(T)\):葉子節點含有的信息熵
過擬合
如果決策樹過於龐大,分支太多,可能造成過擬合。對應訓練樣本都儘可能的分對,也許樣本本身就存在異常點呢?
I. 預剪枝:邊構建,邊剪枝
- 指定深度d
- 節點的min_sample
II. 後剪枝: 構建好後,然後纔開始裁剪
\[ C_\alpha(T) = C(T)+\alpha|T_{leaf}|\]
在構造含一棵樹後,選一些節點做計算,看是否需要剪枝
隨機森林
Bootstraping: 有放回採樣
Bagging:有放回採樣n個樣本,建立分類器
一次採樣一顆樹,多次採樣多棵樹,構成一片森林,多個分類器共同決定。當有一個test時,代入所以的決策樹,共同決策。
隨機性的解釋:
1. 數據的隨機性
爲每個樹選取訓練數據,隨機按照比列有放回選擇數據集
2. 特徵的隨機性
按照比列選取特徵的個數
決策樹單個節點選擇的代碼實現
簡單實現了單個節點決策構造過程
def split(X,y,d,value):
'''
在d緯度上,按照value進行劃分
'''
index_a =(X[:,d]<=value)
index_b =(X[:,d]>value)
return X[index_a],X[index_b],y[index_a],y[index_b]
from collections import Counter
from math import log
from numpy as np
def entropy(y):
counter = Counter(y) # 字典
res = 0.0
for num in counter.values():
p = num/len(y)
res+=-p*log(p)
return res
def gain(X,y,d,v):
X_l,X_r,y_l,y_r = split(X,y,d,v)
e = len(y_l)/len(y)*entropy(y_l)+len(y_r)/len(y)*entropy(y_r)
return (entropy(y)-e)
def gainratio(X,y,d,v):
X_l,X_r,y_l,y_r = split(X,y,d,v)
gain =entropy(y) - len(y_l)/len(y)*entropy(y_l)+len(y_r)/len(y)*entropy(y_r)
return gain/(entropy(y_l)+entropy(y_r))
def gini(y):
counter = Counter(y)
res = 1.0
for num in counter.values():
p = num / len(y)
res += -p**2
return res
#X_l,X_r,y_l,y_r = split(X,y,d,v)
#return 1-(len(y_l)/len(y))**2-(len(y_r)/len(y))**2
def try_split(X,y):
best_entropy = float('inf')
best_d,best_v=-1,-1
for d in range(X.shape[1]):
sorted_index = np.argsort(X[:,d])
for i in range(1, len(X)):
if (X[sorted_index[i],d] != X[sorted_index[i-1],d]):
v = (X[sorted_index[i-1],d]+X[sorted_index[i],d])/2
X_l,X_r,y_l,y_r = split(X,y,d,v)
# 信息熵
e = entropy(y_l)+entropy(y_r)
#gini
e = gini(y_l) + gini(y_r)
# 信息增益
e = -gain(X,y,d,v)
if e < best_entropy:
best_entropy, best_d,best_v = e,d,v
return best_entropy, best_d, best_v
# 手動來劃分
data =np.array([[ 0.3 , 5 , 2 , 0 ],
[ 0.4 , 6 , 0 , 0 ],
[ 0.5 , 6.5 , 1 , 1 ],
[ 0.6 , 6 , 0 , 0 ],
[ 0.7 , 9 , 2 , 1 ],
[ 0.5 , 7 , 1 , 0 ],
[ 0.4 , 6 , 0 , 0 ],
[ 0.6 , 8.5 , 0 , 1 ],
[ 0.3 , 5.5 , 2 , 0 ],
[ 0.9 , 10 , 0 , 1 ],
[ 1 , 12 , 1 , 0 ],
[ 0.6 , 9 , 1 , 0 ],
])
X =data[:,0:3]
y = data[:,-1]
# 手動來劃分
best_entropy, best_d, best_v = try_split(X, y)
print(best_entropy, best_d, best_v)
X1_l, X1_r, y1_l, y1_r = split(X,y,best_d,best_v)
print(X1_l, X1_r, y1_l, y1_r)
best_entropy2, best_d2, best_v2 = try_split(X1_r, y1_r)
X2_l, X2_r, y2_l, y2_r = split(X1_r,y1_r,best_d2,best_v2)
entropy(y2_l)
Python sklean裏面tree模塊裏面的DecisionTreeClassifier
from sklearn import tree
clf =tree.DecisionTreeClassifier(max_depth=1,criterion ='gini') # criterion='entropy|gini'
clf = clf.fit(X,y)
訓練好一顆決策樹之後,我們可以使用export_graphviz導出器以Graphviz格式導出樹。
import graphviz
dot_data = tree.export_graphviz(clf, out_file=None,)
graph = graphviz.Source(dot_data)
graph.render("data")
在運行時可以出錯:
ExecutableNotFound: failed to execute ['dot', '-Tpdf', '-O', 'data'], make sure the Graphviz executables are on your systems' PATH
原因:graphviz本身是一個軟件,需要額外下載,並將其bin加入環境變量之中。下載