機器學習西瓜書吃瓜筆記之(二)決策樹分類 附一鍵生成決策樹&視覺化python程式碼實現
決策樹分類(附一鍵生成視覺化python程式碼實現)
決策樹
-
決策樹是用於分類任務的樹結構,它的葉子結點為類別,其餘節點為判斷操作。
-
決策樹類似於日常中判斷分類的方法。對某個樣本進行分類時:
- 從根節點開始
- 得到所處節點的判斷結果
- 移動到滿足結果的子節點上
- 當移動到葉子結點上時,返回類別,否則轉第2步
-
研究決策樹,重點在於如何構建決策樹。
構建
決策樹學習基本演算法:
輸入:
訓練集 D={(X1,y1),(X2,y2),...,(Xm,ym)}
屬性集 A={a1,a2,...,ad}
過程:函式 TreeGenerate(D,A)
生成結點 node;
if D中樣本全屬於同一類別C then
將node標記為C類葉結點; return
end if
if A=∅ or D中樣本在A上取值相同 then
將node標記為葉結點,其類別標記為D中樣本數最多的類; return
end if
從A中選擇最優劃分屬性a*;
for a* 的每一個值 a*_v do
為node生成一個分支; 令Dv表示D中在a*上取值為a*_v的樣本子集;
if Dv 為空 then
將分支結點標記為葉結點,其類別標記為D中樣本最多的類; return
else
以TreeGenerate(D, A \ {a*})為分支結點
end if
end for
輸出:以node為根結點的一棵決策樹
演算法中最關鍵的是如何從 A A A中選擇最優劃分屬性 a ∗ a^* a∗,不同的劃分選擇決定了決策樹的種類:
- 資訊增益 ⇒ ID3決策樹
- 資訊增益率 ⇒ C4.5決策樹
- 基尼指數 ⇒ CART決策樹
資訊熵
通俗理解資訊熵 - 知乎
資訊熵是度量樣本集合純度最常用的指標。假定當前樣本集合
D
D
D中第
i
i
i類樣本所佔比例為
p
i
(
i
=
1
,
2
,
⋯
,
n
)
p_i(i=1,2,\cdots,n)
pi(i=1,2,⋯,n),則
D
D
D的資訊熵定義為:
H
(
X
)
=
−
∑
i
=
1
n
p
(
x
i
)
⋅
l
o
g
p
(
x
i
)
H(X)=-\sum_{i=1}^{n}p(x_i)·logp(x_i)
H(X)=−i=1∑np(xi)⋅logp(xi)
- 越小概率的事情發生了產生的資訊量越大
- 熵則是在結果出來之前對可能產生的資訊量的期望
- 資訊熵描述隨機變數的不確定性,資訊熵越小,資料集不確定性就低
條件熵
通俗理解條件熵 - 知乎
條件熵代表在某一個條件下,隨機變數的複雜度(不確定度)
H
(
Y
∣
X
)
=
−
∑
x
∈
X
p
(
x
)
⋅
H
(
Y
∣
X
=
x
)
=
−
∑
x
∈
X
p
(
x
)
∑
y
∈
Y
p
(
y
∣
x
)
⋅
l
o
g
p
(
y
∣
x
)
=
−
∑
x
∈
X
∑
y
∈
Y
p
(
x
,
y
)
l
o
g
p
(
y
∣
x
)
\begin{aligned} H(Y|X)&=-\sum_{x\in X}p(x)·H(Y|X=x)\\ &=-\sum_{x\in X}p(x)\sum_{y\in Y}p(y|x)·logp(y|x)\\ &=-\sum_{x\in X}\sum_{y\in Y}p(x,y)logp(y|x) \end{aligned}
H(Y∣X)=−x∈X∑p(x)⋅H(Y∣X=x)=−x∈X∑p(x)y∈Y∑p(y∣x)⋅logp(y∣x)=−x∈X∑y∈Y∑p(x,y)logp(y∣x)
- 條件熵是指在給定某個變數為某個值的情況下,另一個變數的熵是多少
- 在每一個小類裡面,都計算一個小熵,然後每一個小熵乘以各個類別的概率,然後求和,得到條件熵
資訊增益
X的熵減去Y條件下X的熵,就是資訊增益:
G
a
i
n
(
X
,
Y
)
=
H
(
X
)
−
H
(
Y
∣
X
)
Gain(X,Y) = H(X)-H(Y|X)
Gain(X,Y)=H(X)−H(Y∣X)
決策樹生成&視覺化
- 直接複製貼上就可以執行看結果,說不清楚的地方請看我的程式碼具體實現,關鍵部分已經全部加上註釋。
- 視覺化部分需要安裝graphviz包,具體請百度安裝教程(pip一下,官網下載release版本解壓再把路徑加環境path就行了)。
- 要是視覺化報錯
Error: Could not open "decisionTree.gv.pdf" for writing : Invalid argument'
記得在瀏覽器關閉之前的檢視
from random import choice
from collections import Counter
import math
# ==========
# 定義資料集
# ==========
D = [
{'色澤': '青綠', '根蒂': '蜷縮', '敲聲': '濁響', '紋理': '清晰', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '烏黑', '根蒂': '蜷縮', '敲聲': '沉悶', '紋理': '清晰', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '烏黑', '根蒂': '蜷縮', '敲聲': '濁響', '紋理': '清晰', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '青綠', '根蒂': '蜷縮', '敲聲': '沉悶', '紋理': '清晰', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '淺白', '根蒂': '蜷縮', '敲聲': '濁響', '紋理': '清晰', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '青綠', '根蒂': '稍蜷', '敲聲': '濁響', '紋理': '清晰', '臍部': '稍凹', '觸感': '軟粘', '好瓜': '是'},
{'色澤': '烏黑', '根蒂': '稍蜷', '敲聲': '濁響', '紋理': '稍糊', '臍部': '稍凹', '觸感': '軟粘', '好瓜': '是'},
{'色澤': '烏黑', '根蒂': '稍蜷', '敲聲': '濁響', '紋理': '清晰', '臍部': '稍凹', '觸感': '硬滑', '好瓜': '是'},
{'色澤': '烏黑', '根蒂': '稍蜷', '敲聲': '沉悶', '紋理': '稍糊', '臍部': '稍凹', '觸感': '硬滑', '好瓜': '否'},
{'色澤': '青綠', '根蒂': '硬挺', '敲聲': '清脆', '紋理': '清晰', '臍部': '平坦', '觸感': '軟粘', '好瓜': '否'},
{'色澤': '淺白', '根蒂': '硬挺', '敲聲': '清脆', '紋理': '模糊', '臍部': '平坦', '觸感': '硬滑', '好瓜': '否'},
{'色澤': '淺白', '根蒂': '蜷縮', '敲聲': '濁響', '紋理': '模糊', '臍部': '平坦', '觸感': '軟粘', '好瓜': '否'},
{'色澤': '青綠', '根蒂': '稍蜷', '敲聲': '濁響', '紋理': '稍糊', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '否'},
{'色澤': '淺白', '根蒂': '稍蜷', '敲聲': '沉悶', '紋理': '稍糊', '臍部': '凹陷', '觸感': '硬滑', '好瓜': '否'},
{'色澤': '烏黑', '根蒂': '稍蜷', '敲聲': '濁響', '紋理': '清晰', '臍部': '稍凹', '觸感': '軟粘', '好瓜': '否'},
{'色澤': '淺白', '根蒂': '蜷縮', '敲聲': '濁響', '紋理': '模糊', '臍部': '平坦', '觸感': '硬滑', '好瓜': '否'},
{'色澤': '青綠', '根蒂': '蜷縮', '敲聲': '沉悶', '紋理': '稍糊', '臍部': '稍凹', '觸感': '硬滑', '好瓜': '否'},
]
# ==========
# 決策樹生成類
# ==========
class DecisionTree:
def __init__(self, D, label, chooseA):
self.D = D # 資料集
self.label = label # 哪個屬性作為標籤
self.chooseA = chooseA # 劃分方法
self.A = list(filter(lambda key: key != label, D[0].keys())) # 屬性集合A
# 獲得A的每個屬性的可選項
self.A_item = {}
for a in self.A:
self.A_item.update({a: set(self.getClassValues(D, a))})
self.root = self.generate(self.D, self.A) # 生成樹並儲存根節點
# 獲得D中所有className屬性的值
def getClassValues(self, D, className):
return list(map(lambda sample: sample[className], D))
# D中樣本是否在A的每個屬性上相同
def isSameInA(self, D, A):
for a in A:
types = set(self.getClassValues(D, a))
if len(types) > 1:
return False
return True
# 構建決策樹,遞迴生成節點
def generate(self, D, A):
node = {} # 生成節點
remainLabelValues = self.getClassValues(D, self.label) # D中的所有標籤
remainLabelTypes = set(remainLabelValues) # D中含有哪幾種標籤
if len(remainLabelTypes) == 1:
# 當前節點包含的樣本全屬於同個類別,無需劃分
return remainLabelTypes.pop() # 標記Node為葉子結點,值為僅存的標籤
most = max(remainLabelTypes, key=remainLabelValues.count) # D佔比最多的標籤
if len(A) == 0 or self.isSameInA(D, A):
# 當前屬性集為空,或是所有樣本在所有屬性上取值相同,無法劃分
return most # 標記Node為葉子結點,值為佔比最多的標籤
a = self.chooseA(D,A,self) # 劃分選擇
for type in self.A_item[a]:
condition = (lambda sample: sample[a] == type) # 決策條件
remainD = list(filter(condition, D)) # 剩下的樣本
if len(remainD) == 0:
# 當前節點包含的樣本集為空,不能劃分
node.update({type: most}) # 標記Node為葉子結點,值為佔比最多的標籤
else:
# 繼續對剩下的樣本按其餘屬性劃分
remainA = list(filter(lambda x: x != a, A)) # 未使用的屬性
_node = self.generate(remainD, remainA) # 遞迴生成子代節點
node.update({type: _node}) # 把生成的子代節點更新到當前節點
return {a: node}
# ==========
# 定義劃分方法
# ==========
# 隨機選擇
def random_choice(D, A, tree: DecisionTree):
return choice(A)
# 資訊熵
def Ent(D,label,a,a_v):
D_v = filter(lambda sample:sample[a]==a_v,D)
D_v = map(lambda sample:sample[label],D_v)
D_v = list(D_v)
D_v_length = len(D_v)
counter = Counter(D_v)
info_entropy = 0
for k, v in counter.items():
p_k = v / D_v_length
info_entropy += p_k * math.log(p_k, 2)
return -info_entropy
# 資訊增益
def information_gain(D, A, tree: DecisionTree):
gain = {}
for a in A:
gain[a] = 0
values = tree.getClassValues(D, a)
counter = Counter(values)
for a_v,nums in counter.items():
gain[a] -= (nums / len(D)) * Ent(D,tree.label,a,a_v)
return max(gain.keys(),key=lambda key:gain[key])
# ==========
# 建立決策樹
# ==========
desicionTreeRoot = DecisionTree(D, label='好瓜',chooseA=information_gain).root
print('決策樹:', desicionTreeRoot)
# ==========
# 決策樹視覺化類
# ==========
class TreeViewer:
def __init__(self):
from graphviz import Digraph
self.id_iter = map(str, range(0xffff))
self.g = Digraph('G', filename='decisionTree.gv')
def create_node(self, label, shape=None):
id = next(self.id_iter)
self.g.node(name=id, label=label, shape=shape, fontname="Microsoft YaHei")
return id
def build(self, key, node, from_id):
for k in node.keys():
v = node[k]
if type(v) is dict:
first_attr = list(v.keys())[0]
id = self.create_node(first_attr+"?", shape='box')
self.g.edge(from_id, id, k, fontsize = '12', fontname="Microsoft YaHei")
self.build(first_attr, v[first_attr], id)
else:
id = self.create_node(v)
self.g.edge(from_id, id, k, fontsize = '12', fontname="Microsoft YaHei")
def show(self, root):
first_attr = list(root.keys())[0]
id = self.create_node(first_attr+"?", shape='box')
self.build(first_attr, root[first_attr], id)
self.g.view()
# ==========
# 顯示建立的決策樹
# ==========
viewer = TreeViewer()
viewer.show(desicionTreeRoot)
敲程式碼不易,且用且珍惜,若要轉載請註明出處,謝謝
相關文章
- 【Python機器學習實戰】決策樹和整合學習(二)——決策樹的實現Python機器學習
- 【西瓜書筆記】3. 決策樹筆記
- 【機器學習】實現層面 決策樹 並用graphviz視覺化樹機器學習視覺化
- 機器學習——決策樹模型:Python實現機器學習模型Python
- 機器學習之 決策樹(Decision Tree)python實現機器學習Python
- 機器學習筆記(四)決策樹機器學習筆記
- Python機器學習:決策樹001什麼是決策樹Python機器學習
- 機器學習之決策樹機器學習
- 機器學習之決策樹ID3(python實現)機器學習Python
- 機器學習|決策樹-sklearn實現機器學習
- 機器學習西瓜書02:第四章,決策樹。機器學習
- 機器學習:決策樹機器學習
- 【Python機器學習實戰】決策樹和整合學習(一)Python機器學習
- 機器學習——決策樹模型機器學習模型
- 《機器學習Python實現_09_02_決策樹_CART》機器學習Python
- 機器學習之決策樹在sklearn中的實現機器學習
- 分類——決策樹模型模型
- 機器學習之決策樹演算法機器學習演算法
- 機器學習之決策樹原理和sklearn實踐機器學習
- 決策樹模型(3)決策樹的生成與剪枝模型
- 機器學習Sklearn系列:(三)決策樹機器學習
- 機器學習實戰(三)決策樹ID3:樹的構建和簡單分類機器學習
- 【機器學習】--決策樹和隨機森林機器學習隨機森林
- 機器學習之決策樹詳細講解及程式碼講解機器學習
- 深入淺出學習決策樹(二)
- 機器學習之使用sklearn構造決策樹模型機器學習模型
- 機器學習經典演算法之決策樹機器學習演算法
- 機器學習 Day 9 | 決策樹基礎機器學習
- 【Python機器學習實戰】決策樹與整合學習(三)——整合學習(1)Python機器學習
- 決策樹學習總結
- 深入淺出學習決策樹(一)
- 圖解機器學習 | 決策樹模型詳解圖解機器學習模型
- 決策樹
- 決策樹在機器學習的理論學習與實踐機器學習
- 【Python機器學習實戰】決策樹與整合學習(四)——整合學習(2)GBDTPython機器學習
- 《統計學習方法》——從零實現決策樹
- 機器學習(五):通俗易懂決策樹與隨機森林及程式碼實踐機器學習隨機森林
- 人工智慧之機器學習基礎——決策樹(Decision Tree)人工智慧機器學習