上一篇文章中主要介紹瞭如下幾方面:html
本文以一個新的數據集(隱形眼鏡數據集)爲基礎實現構建決策樹、決策樹的保存與加載、利用決策樹分類、決策樹的可視化,前文的知識不在過多概述,着重介紹這四個方面。python
先大體瞭解一下數據集:
這份數據源至UCI數據庫,其共有4個特徵分別爲age(年齡)、prescript(症狀)、astigmatic(閃光)、tearRate(淚液產生率)以及一個分類標籤class,該分類包含硬材質、軟材質和不該配帶三種。git
爲了方便處理,對樣本作如下處理:算法
在構造決策樹以前,先回顧一下前幾個子模塊的工做原理:先獲取原始數據集,而後基於最優特徵劃分數據集,當數據集特徵大於兩個時,第一次劃分以後,數據將被向下傳遞至樹的下一個節點,在這個節點上,在此劃分數據,此過程是利用遞歸原理處理數據集。數據庫
何時劃分結束呢?當程序遍歷完全部劃分數據集的屬性,或者每一個分支下全部實例分類一致時表明劃分數據集結束。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節點的子節點。
這些值多是類標籤,也多是另外一個字典。若是值是類標籤,則該子節點爲葉子節點;若是值是另外一個字典,則該子節點是一個判斷節點,經過這類格式不斷重複就構成了一棵決策樹。
決策樹的保存有不少種方法,但原理都是同樣的,即序列化與反序列化,這裏介紹如下兩種方法。
#第一種方法 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方法便可加載數據,這裏須要注意,不論寫入仍是讀取時,都須要以二進制的格式,否則會發生報錯。
構造決策樹以後,能夠將它用於實際數據的分類,在執行數據分類時,須要傳入決策樹、特徵標籤列表和用於分類的測試數據。而後程序會比較測試數據與決策樹上的數值,遞歸執行該過程直到進入葉子節點,最後獲得的分類結果就是葉子節點所屬類型。
代碼以下:
#傳入的數據爲決策樹、數據集特徵標籤、測試數據 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 '''
執行該函數,能夠將傳入的數據與原文中的數據進行比對,獲得的分類結果是一致的。
決策樹的主要優勢就是直觀易於理解,若是不能將其直觀地顯示出來,就沒法發揮其優點。但經過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,最後獲得的可視化圖片以下:
綜上有關決策樹的相關知識介紹完畢,整體來講,這個分類算法仍是易於理解的,但它是十分重要的,由於它爲後面學習隨機森林奠基了基礎,每個算法都有各自的適合環境,而決策樹也有本身的優缺點。
決策樹的優勢:
決策樹的缺點:
公衆號【奶糖貓】後臺回覆「隱形眼鏡」便可獲取源碼和數據供參考,感謝閱讀。