python决策树可视化_「决策树」| Part3—Python实现之可视化
文章首發于微信公眾號:AlgorithmDeveloper,專注機器學習與Python,編程與算法,還有生活。
1.前言
「決策樹」| Part2—Python實現之構建決策樹中我們已經可以基于給定數據集訓練出決策樹模型,只不過是以字典方式表示決策樹,決策樹直觀、易于理解的優點完全體現不出來。因此,這篇文章的目的就是將訓練出的決策樹模型以樹狀圖形表示。
給定數據集:
字典形式決策樹模型:
{'人品': {'好': '見 ', '差': {'富有': {'沒錢': '不見', '有錢': {'外貌': {'漂亮': '見 ', '丑': '不見'}}}}}}
2.獲取決策樹的葉節點數及深度
為了使繪制出的決策樹圖形不因樹的節點、深度的增減而變得畸形,因此利用決策樹的葉子節點個數以及樹的深度將x軸、y軸平均切分,從而使樹狀圖平均分布在畫布上。
#獲取決策樹葉節點個數
def getNumLeafs(tree):
numLeafs = 0
#獲取第一個節點的分類特征
firstFeat = list(tree.keys())[0]
#得到firstFeat特征下的決策樹(以字典方式表示)
secondDict = tree[firstFeat]
#遍歷firstFeat下的每個節點
for key in secondDict.keys():
#如果節點類型為字典,說明該節點下仍然是一棵樹,此時遞歸調用getNumLeafs
if type(secondDict[key]).__name__== 'dict':
numLeafs += getNumLeafs(secondDict[key])
#否則該節點為葉節點
else:
numLeafs += 1
return numLeafs
#獲取決策樹深度
def getTreeDepth(tree):
maxDepth = 0
#獲取第一個節點分類特征
firstFeat = list(tree.keys())[0]
#得到firstFeat特征下的決策樹(以字典方式表示)
secondDict = tree[firstFeat]
#遍歷firstFeat下的每個節點,返回子樹中的最大深度
for key in secondDict.keys():
#如果節點類型為字典,說明該節點下仍然是一棵樹,此時遞歸調用getTreeDepth,獲取該子樹深度
if type(secondDict[key]).__name__ == 'dict':
thisDepth = 1 + getTreeDepth(secondDict[key])
else:
thisDepth = 1
if thisDepth > maxDepth:
maxDepth = thisDepth
return maxDepth
3.繪制決策樹
3.1繪制節點
#繪制決策樹
import matplotlib.pyplot as plt
def createPlot(tree):
#定義一塊畫布,背景為白色
fig = plt.figure(1, facecolor='white')
#清空畫布
fig.clf()
#不顯示x、y軸刻度
xyticks = dict(xticks=[],yticks=[])
#frameon:是否繪制坐標軸矩形
createPlot.pTree = plt.subplot(111, frameon=False, **xyticks)
#計算決策樹葉子節點個數
plotTree.totalW = float(getNumLeafs(tree))
#計算決策樹深度
plotTree.totalD = float(getTreeDepth(tree))
#最近繪制的葉子節點的x坐標
plotTree.xOff = -0.5/plotTree.totalW
#當前繪制的深度:y坐標
plotTree.yOff = 1.0
#(0.5,1.0)為根節點坐標
plotTree(tree,(0.5,1.0),'')
plt.show()
#定義決策節點以及葉子節點屬性:boxstyle表示文本框類型,sawtooth:鋸齒形;fc表示邊框線粗細
decisionNode = dict(boxstyle="sawtooth", fc="0.5")
leafNode = dict(boxstyle="round4", fc="0.5")
#定義箭頭屬性
arrow_args = dict(arrowstyle="
#nodeText:要顯示的文本;centerPt:文本中心點,即箭頭所在的點;parentPt:指向文本的點;nodeType:節點屬性
#ha='center',va='center':水平、垂直方向中心對齊;bbox:方框屬性
#arrowprops:箭頭屬性
#xycoords,textcoords選擇坐標系;axes fraction-->0,0是軸域左下角,1,1是右上角
def plotNode(nodeText, centerPt, parentPt, nodeType):
createPlot.pTree.annotate(nodeText, xy=parentPt, xycoords="axes fraction",
xytext=centerPt, textcoords='axes fraction',
va='center',ha='center',bbox=nodeType, arrowprops=arrow_args)
def plotMidText(centerPt,parentPt,midText):
xMid = (parentPt[0] - centerPt[0])/2.0 + centerPt[0]
yMid = (parentPt[1] - centerPt[1])/2.0 + centerPt[1]
createPlot.pTree.text(xMid, yMid, midtext)
plotNode函數一次繪制的是一個箭頭與一個節點,plotMidText函數繪制的是直線中點上的文本。
3.2遞歸繪制決策樹
遞歸繪制決策樹的整體思路如下:
(1)繪制當前節點;
(2)如果當前節點的子節點不是葉子節點,則遞歸;
(3)如果當前節點的子節點是葉子節點,則繪制。
def plotTree(tree, parentPt, nodeTxt):
#計算葉子節點個數
numLeafs = getNumLeafs(tree)
#獲取第一個節點特征
firstFeat = list(tree.keys())[0]
#計算當前節點的x坐標
centerPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)
#繪制當前節點
plotMidText(centerPt,parentPt,nodeTxt)
plotNode(firstFeat,centerPt,parentPt,decisionNode)
secondDict = tree[firstFeat]
#計算繪制深度
plotTree.yOff -= 1.0/plotTree.totalD
for key in secondDict.keys():
#如果當前節點的子節點不是葉子節點,則遞歸
if type(secondDict[key]).__name__ == 'dict':
plotTree(secondDict[key],centerPt,str(key))
#如果當前節點的子節點是葉子節點,則繪制該葉節點
else:
#plotTree.xOff在繪制葉節點坐標的時候才會發生改變
plotTree.xOff += 1.0/plotTree.totalW
plotNode(secondDict[key], (plotTree.xOff,plotTree.yOff),centerPt,leafNode)
plotMidText((plotTree.xOff,plotTree.yOff),centerPt,str(key))
plotTree.yOff += 1.0/plotTree.totalD
根據決策樹的葉子節點數和深度來平均切分畫布,并且x、y軸的總長度為1,如下圖所示:
原諒我的畫圖水平
3.2.1在createPlot函數中:
plotTree.totalW :表示葉子節點個數,因此上圖中每兩個葉子節點之間的距離為:1/plotTree.totalW;
plotTree.totalD :表示決策樹深度;
plotTree.xOff:表示最近繪制的葉子節點x坐標,在繪制葉節點時其值才會更新;其初始值為圖中虛線圓圈位置,這樣在以后確定葉子節點位置時可以直接加整數倍的1/plotTree.totalW;
plotTree.yOff = 1.0 :表示當前繪制的深度,其值初始化為根節點y坐標。
3.2.2在plotTree函數中:
#計算當前節點的x坐標
centerPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)
在確定當前節點x坐標時,只需確定當前節點下的葉節點個數,其x坐標即為葉節點所占距離的一半:float(numLeafs)/2.0/plotTree.totalW;
由于plotTree.xOff初始值為-0.5/plotTree.totalW,因此當前節點x坐標還需加上0.5/plotTree.totalW。
4.決策樹可視化
#決策樹節點文本可以以中文顯示
import matplotlib as mpl
mpl.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
mpl.rcParams['axes.unicode_minus'] = False
#創建數據集
def createDataSet():
dataSet = [['有錢','好','漂亮','見 '],
['有錢','差','漂亮','見 '],
['有錢','差','丑','不見'],
['沒錢','好','丑','見 '],
['沒錢','差','漂亮','不見'],
['沒錢','好','漂亮','見 ']]
labels = ['富有','人品','外貌']
return dataSet, labels
dataSet, dataLabels = createDataSet()
#創建決策樹
myTree = createDecideTree(dataSet,dataLabels)
print(myTree)
#繪制決策樹
createPlot(myTree)
字典形式表示決策樹:
{'人品': {'好': '見 ', '差': {'富有': {'沒錢': '不見', '有錢': {'外貌': {'漂亮': '見 ', '丑': '不見'}}}}}}
樹狀圖形決策樹:
5.使用決策樹算法
在已知對方有錢,人品差,長得漂亮后,利用前面訓練的決策樹做出決策,見或不見?!
#使用決策樹進行分類
def classify(tree,feat,featValue):
firstFeat = list(tree.keys())[0]
secondDict = tree[firstFeat]
featIndex = feat.index(firstFeat)
for key in secondDict.keys():
if featValue[featIndex] == key:
if type(secondDict[key]).__name__ == 'dict':
classLabel = classify(secondDict[key],feat,featValue)
else:
classLabel = secondDict[key]
return classLabel
feat = ['富有','人品','外貌']
featValue = ['有錢','差','漂亮']
print(classify(myTree,feat,featValue))
決策結果:
見
6.存儲決策樹模型
構建決策樹消耗的時間還是很可觀的,尤其在數據量大的時候,因此,當訓練完決策樹模型后有必要將其保存下來,以便后續使用。使用Python模塊的pickle序列化對象可以解決這個問題,序列化對象可以在磁盤上保存對象,在需要時將其讀取出來。
#保存決策樹模型
import pickle
def saveTree(tree, fileName):
fw = open(fileName,'wb')
pickle.dump(tree, fw)
fw.close()
#加載決策樹模型
def loadTree(fileName):
fr = open(fileName,'rb')
return pickle.load(fr)
saveTree((myTree),'myTree.txt')
print(loadTree('myTree.txt'))
{'人品': {'差': {'富有': {'有錢': {'外貌': {'丑': '不見', '漂亮': '見 '}}, '沒錢': '不見'}}, '好': '見 '}}
Coding Your Ambition!
總結
以上是生活随笔為你收集整理的python决策树可视化_「决策树」| Part3—Python实现之可视化的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: st东电是什么公司
 - 下一篇: python论坛app_理解python