決策樹的構建及可視化——幫本身配副隱形眼鏡

前文簡介

上一篇文章中主要介紹瞭如下幾方面:html

  • 決策樹的簡介
  • 決策樹的流程
  • 熵的定義及如何計算熵
  • 信息增益的定義及如何計算信息增益
  • 依據信息增益劃分數據集

本文以一個新的數據集(隱形眼鏡數據集)爲基礎實現構建決策樹、決策樹的保存與加載、利用決策樹分類、決策樹的可視化,前文的知識不在過多概述,着重介紹這四個方面。python

先大體瞭解一下數據集:
在這裏插入圖片描述
這份數據源至UCI數據庫,其共有4個特徵分別爲age(年齡)、prescript(症狀)、astigmatic(閃光)、tearRate(淚液產生率)以及一個分類標籤class,該分類包含硬材質、軟材質和不該配帶三種。git

爲了方便處理,對樣本作如下處理:算法

  1. age:young—>0、pre—>一、presbyopic—>2
  2. prescript:myope—>0、hyper—>1
  3. astigmatic:no—>0、yes—>1
  4. tearRate:reduced—>0、normal—>1

4、決策樹的構建

在構造決策樹以前,先回顧一下前幾個子模塊的工做原理:先獲取原始數據集,而後基於最優特徵劃分數據集,當數據集特徵大於兩個時,第一次劃分以後,數據將被向下傳遞至樹的下一個節點,在這個節點上,在此劃分數據,此過程是利用遞歸原理處理數據集。數據庫

何時劃分結束呢?當程序遍歷完全部劃分數據集的屬性,或者每一個分支下全部實例分類一致時表明劃分數據集結束。windows

而構造決策樹的過程就是將每一次劃分出的數據填入一個字典中,當數據集劃分結束時,向字典中填充數據也結束,此過程也是一個遞歸過程,至此決策樹的構造完成。
代碼以下:app

def CreateTree(DataSet):
    #獲取全部特徵標籤
    index_list = list(DataSet.columns)
    #獲取最後一列(分類標籤)的類別
    label_series = DataSet.iloc[:,-1].value_counts()
    #判斷類別標籤最多一個是否等於數據樣本數、或者數據集是否只有一列
    if label_series[0]==DataSet.shape[0] or DataSet.shape[1] == 1:
        return label_series.index[0] #返回類標籤
    # 獲取最優特徵列索引
    col = ChooseBF(DataSet)
    # 獲取最優特徵
    BestFeature = index_list[col]
    #將最優特徵依次填入字典中
    TheTree = {BestFeature:{}}
    # 從標籤列表中刪去該特徵標籤
    del index_list[col]
    #提取最佳切分列的全部屬性值
    value_list = set(DataSet.iloc[:,col])
    #利用遞歸方法建樹,每次對象爲當前最優特徵
    for value in value_list:
        TheTree[BeatFeature][value] = CreateTree(splitSet(DataSet,col,value))
    return TheTree

遞歸函數的第一個中止條件是全部的類標籤都相同,遞歸函數第二個中止條件是使用完數據集中全部的特徵,即數據集不能繼續劃分;字典變量TheTree儲存了樹的全部信息,BestFeature則是當前最優特徵。ide

最後代碼遍歷當前最優特徵的全部屬性值,在每一個數據集劃分上遞歸調用函數CreateTree(),而且傳入的參數是每次劃分以後的數據集,獲得的返回值都會被插入字典TheTree中,遞歸結束後,字典中將會嵌套不少表明葉子節點信息的數據。函數

獲得TheTree字典以下:工具

{'tearRate': {0: 'no lenses', 1: {'astigmatic': {0: {'age': {0: 'soft', 1: 'soft', 2: {'prescript': {0: 'no lenses', 1: 'soft'}}}}, 1: {'prescript': {0: 'hard', 1: {'age': {0: 'hard', 1: 'no lenses', 2: 'no lenses'}}}}}}}}

從左邊開始,第一個關鍵字key爲tearRate,這表明在全部特徵中,tearRate特徵的信息增益最大,在此特徵下,數據降低(劃分)最快,該關鍵字的值也是一個字典。第二個關鍵字是依據tearRate特徵劃分的數據集,這些關鍵字的值就是tearRate節點的子節點。

這些值多是類標籤,也多是另外一個字典。若是值是類標籤,則該子節點爲葉子節點;若是值是另外一個字典,則該子節點是一個判斷節點,經過這類格式不斷重複就構成了一棵決策樹。

5、決策樹的保存與加載

決策樹的保存有不少種方法,但原理都是同樣的,即序列化與反序列化,這裏介紹如下兩種方法。

#第一種方法
np.save('TheTree.npy',TheTree)
read_tree = np.load('TheTree.npy',allow_pickle=True).item()

第一種方法是利用numpy庫中的save方法,能夠將字典格式的決策樹保存爲npy文件;當讀取樹時,須要在方法後加上item(),由於咱們存儲的數據是字典類型,如果矩陣類型則需刪去。

#第二種方法
import pickle
def storeTree(inputTree, filename):
    fw = open(filename,'wb')
    pickle.dump(inputTree,fw)
    fw.close()
def grabTree(filename):
    fr = open(filename,'rb')
    return pickle.load(fr)

第二種方法是利用pickle庫的dump方法對數據序列化,在讀取時,用load方法便可加載數據,這裏須要注意,不論寫入仍是讀取時,都須要以二進制的格式,否則會發生報錯。

6、利用決策樹分類

構造決策樹以後,能夠將它用於實際數據的分類,在執行數據分類時,須要傳入決策樹、特徵標籤列表和用於分類的測試數據。而後程序會比較測試數據與決策樹上的數值,遞歸執行該過程直到進入葉子節點,最後獲得的分類結果就是葉子節點所屬類型。
代碼以下:

#傳入的數據爲決策樹、數據集特徵標籤、測試數據
def classify(inputTree,labels,testVec):
    #獲取決策樹的第一個節點
    FirstStr = list(inputTree.keys())[0]
    #取第一個節點外下一個字典
    SecondDict = inputTree[FirstStr]
    '''
    {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
    {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}
    {0: 'no', 1: 'yes'}
    '''
    #取第一個節點在labels裏的索引
    feat_index = labels.index(FirstStr)
    #遍歷字典中的key
    for key in SecondDict.keys():
        #比較testVec裏的值與樹節點的值,若是達到葉子節點,返回類標籤
        if testVec[feat_index]==key:
            #若是下一個字典中的仍包含字典,則遞歸繼續比較
            if type(SecondDict[key])==dict :
                classlabel = classify(SecondDict[key],labels,testVec)
            else:
                #直到最後取到類標籤
                classlabel = SecondDict[key]
    return classlabel

其中傳入特徵標籤列表labels的做用是幫助肯定每次最優特徵在數據集中的索引,利用index方法查找當前列表中第一個匹配FirstStr變量的元素,而後代碼遞歸遍歷整棵樹,比較測試數據testVec變量中的值與樹節點的值,直到達到葉子節點,返回當前節點的分類標籤。

這裏利用了上篇文章的數據構造的樹作一個SecondDict舉例,它的做用就是獲取當前字典中最優特徵(第一個關鍵字)的值,以達到與測試數據遞歸比較的效果。

classlabel = classify(inputTree,labels,[0,1,0,0])
'''
no lenses
'''

執行該函數,能夠將傳入的數據與原文中的數據進行比對,獲得的分類結果是一致的。

7、決策樹可視化

決策樹的主要優勢就是直觀易於理解,若是不能將其直觀地顯示出來,就沒法發揮其優點。但經過matplotlib庫繪製決策樹是一個十分複雜的過程,這裏偷懶介紹另外一種比較簡易的方法。

Graphviz是一種圖形繪製工具,能夠繪製出不少圖形結構,但傳入的數據須要的是dot格式,因此這裏利用sklearn生成的決策樹進行可視化。

Graphviz下載地址中下載graphviz-2.38.msi文件,在安裝結束後須要配置環境,將該文件夾的路徑添加至系統變量的Path中,在cmd中輸入dot -version出現版本信息則表明安裝配置成功。
在這裏插入圖片描述
決策樹可視化代碼以下:

from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
import pydotplus
import graphviz
def pic_tree(DataSet):
    #全部特徵數據
    feature_train = DataSet.iloc[:, :-1]
    #類標籤數據
    the_label = DataSet.iloc[:, -1]
    #unique將類標籤去重
    labels = the_label.unique().tolist()
    #以類標籤的在列表中的索引代替該標籤——轉化成數字
    the_label = the_label.apply(lambda x: labels.index(x))
    #訓練數據
    clf = DecisionTreeClassifier()
    clf = clf.fit(feature_train, the_label)
    #繪圖過程
    dot_data = tree.export_graphviz(clf, out_file=None, feature_names=['age','prescript','astigmatic','tearRate'],
                                    class_names=['no lenses', 'soft','hard'], filled=True, rounded=True,
                                    special_characters=True)
    # 兩種方法
    # 1.利用graphviz庫生成PDF圖片
    pic = graphviz.Source(dot_data)
    pic.render('lense')
    # 2.利用pydotplus庫將Dot格式轉成PDF
    #graph = pydotplus.graph_from_dot_data(dot_data)
    #return graph.write_pdf("lense.pdf")

這裏生成決策樹圖片時也有兩種方法,第一種是利用graphviz庫的Source方法生成PDF圖片,第二種須要利用pydotplus庫將Dot格式轉成PDF,最後獲得的可視化圖片以下:
在這裏插入圖片描述

總結

綜上有關決策樹的相關知識介紹完畢,整體來講,這個分類算法仍是易於理解的,但它是十分重要的,由於它爲後面學習隨機森林奠基了基礎,每個算法都有各自的適合環境,而決策樹也有本身的優缺點。

決策樹的優勢:

  • 計算複雜度不高,輸出結果易於理解。
  • 對中間缺失值不敏感。
  • 能夠處理不相關特徵數據。
  • 樹能實現圖形化。

決策樹的缺點:

  • 當決策樹過於複雜時,會出現過分擬合狀況。
  • 比較不穩定,數據發生比較小的變化時也會致使生成不一樣的樹。
  • 在樣本不均衡時,權重不一樣會致使樹出現誤差。

公衆號【奶糖貓】後臺回覆「隱形眼鏡」便可獲取源碼和數據供參考,感謝閱讀。

相關文章
相關標籤/搜索