決策樹之python實現ID3算法(例子)


 引言

決策樹從本質上是從訓練數據集上訓練處一組分類規則,完全依據訓練數據,所得規則容易發生過擬合,這也是決策樹的缺點,不過可以通過決策樹的剪枝,來提高決策樹的泛化能力。

由此,決策樹的創建可包括三部分:特征選擇、決策樹的生成以及決策樹的剪枝;決策樹的應用包括:分類、回歸以及特征選擇。 

決策樹最經典的算法包括:ID3、C4.5以及CART算法,ID3與C4.5算法相似,C4.5在特征選擇時選用的信息准則是信息增益比,而ID3用的是信息增益;因為信息增益偏向於選擇具有較多可能取值的特征

 

基於信息論的特征選擇

注意:熵表示隨機變量的不確定性,熵值越大表示隨機變量含有的信息越少,變量的不確定性越大。 
1) 香儂定義一個數據的信息可按下式計算 (此處是以2為底的對數):

2)熵表示一個數據集合信息的期望,可按下式計算:(該式不理解,可想象下,求變量期望的公式,p(xi) 為變量 xi以及信息 l(xi) 的概率,概率乘以變量(信息)即為變量(信息)的期望)

3)特征 AA 對數據集 DD 的信息增益為:

 上式中,設訓練數據集為D,其樣本容量為|D|,即樣本個數,設共有K個類Ck,k=1,2,...,Ck,k=1,2,...,K , |Ck| 為Ck的樣本個數,

根據特征A 的取值將 D 划分為n個子集D1,D2,...,Dn, |Di|為 Di的樣本數,Dik=Di⋂Ck ,|Dik|為 Dik的樣本個數.

 

如下表和圖所示:

feature1(A) feature1 feature3 labels
a1 b1 c1 y
a1 b2 c2 n
a1 b1 c2 n
a1 b1 c2 n
a2 b1 c1 y
a2 b2 c2 y
a2 b1 c1 n

python實現:

 1 def calcShannonEnt(dataset):#計算熵
 2     numSamples = len(dataset)
 3     labelCounts = {}
 4     for allFeatureVector in dataset:
 5         currentLabel = allFeatureVector[-1]
 6         if currentLabel not in labelCounts.keys():
 7             labelCounts[currentLabel] = 0
 8         labelCounts[currentLabel] += 1
 9     entropy = 0.0
10     for key in labelCounts:
11         property = float(labelCounts[key])/numSamples
12         entropy -= property * log(property,2)
13     return entropy
14 def BestFeatToGetSubdataset(dataset):
15     #下邊這句實現:除去最后一列類別標簽列剩余的列數即為特征個數
16     numFeature = len(dataset[0]) - 1 
17     baseEntropy = calcShannonEnt(dataset)
18     bestInfoGain = 0.0; bestFeature = -1
19     for i in range(numFeature):#i表示該函數傳入的數據集中每個特征
20         # 下邊這句實現抽取特征i在數據集中的所有取值
21         feat_i_values = [example[i] for example in dataset]
22         uniqueValues = set(feat_i_values)
23         feat_i_entropy = 0.0
24         for value in uniqueValues:
25             subDataset = getSubDataset(dataset,i,value)
26             #下邊這句計算pi,實現計算信息增益最大的特征
27             prob_i = len(subDataset)/float(len(dataset))
28             feat_i_entropy += prob_i * calcShannonEnt(subDataset)
29         infoGain_i = baseEntropy - feat_i_entropy
30         if (infoGain_i > bestInfoGain):
31             bestInfoGain = infoGain_i
32             bestFeature = i
33     return bestFeature

 

 

決策樹生成

決策樹生成可用下邊的流程圖表示: 
決策樹生成流程圖

 

ID3算法python實現代碼:

  1 # -*- coding: utf-8 -*-
  2 from math import log
  3 import operator
  4 import pickle
  5 '''
  6 輸入:原始數據集、子數據集(最后一列為類別標簽,其他為特征列)
  7 功能:計算原始數據集、子數據集(某一特征取值下對應的數據集)的香農熵
  8 輸出:float型數值(數據集的熵值)
  9 '''
 10 def calcShannonEnt(dataset):
 11     numSamples = len(dataset)
 12     labelCounts = {}
 13     for allFeatureVector in dataset:
 14         currentLabel = allFeatureVector[-1]
 15         if currentLabel not in labelCounts.keys():
 16             labelCounts[currentLabel] = 0
 17         labelCounts[currentLabel] += 1
 18     entropy = 0.0
 19     for key in labelCounts:
 20         property = float(labelCounts[key])/numSamples
 21         entropy -= property * log(property,2)
 22     return entropy
 23 
 24 '''
 25 輸入:無
 26 功能:封裝原始數據集
 27 輸出:數據集、特征標簽
 28 '''     
 29 def creatDataSet():
 30     dataset = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,0,'no']]
 31     labels = ['no surfacing','flippers']
 32     return dataset,labels
 33 
 34 '''
 35 輸入:數據集、數據集中的某一特征所在列的索引、該特征某一可能取值(例如,(原始數據集、0,1 ))
 36 功能:取出在該特征取值下的子數據集(子集不包含該特征)
 37 輸出:子數據集
 38 '''
 39 def getSubDataset(dataset,colIndex,value):
 40     subDataset = [] #用於存儲子數據集
 41     for rowVector in dataset:
 42         if rowVector[colIndex] == value:
 43             #下邊兩句實現抽取除第colIndex列特征的其他特征取值
 44             subRowVector = rowVector[:colIndex]
 45             subRowVector.extend(rowVector[colIndex+1:])
 46             #將抽取的特征行添加到特征子數據集中
 47             subDataset.append(subRowVector)
 48     return subDataset
 49 
 50 '''
 51 輸入:數據集
 52 功能:選擇最優的特征,以便得到最優的子數據集(可簡單的理解為特征在決策樹中的先后順序)
 53 輸出:最優特征在數據集中的列索引
 54 '''
 55 def BestFeatToGetSubdataset(dataset):
 56     #下邊這句實現:除去最后一列類別標簽列剩余的列數即為特征個數
 57     numFeature = len(dataset[0]) - 1 
 58     baseEntropy = calcShannonEnt(dataset)
 59     bestInfoGain = 0.0; bestFeature = -1
 60     for i in range(numFeature):#i表示該函數傳入的數據集中每個特征
 61         # 下邊這句實現抽取特征i在數據集中的所有取值
 62         feat_i_values = [example[i] for example in dataset]
 63         uniqueValues = set(feat_i_values)
 64         feat_i_entropy = 0.0
 65         for value in uniqueValues:
 66             subDataset = getSubDataset(dataset,i,value)
 67             #下邊這句計算pi
 68             prob_i = len(subDataset)/float(len(dataset))
 69             feat_i_entropy += prob_i * calcShannonEnt(subDataset)
 70         infoGain_i = baseEntropy - feat_i_entropy
 71         if (infoGain_i > bestInfoGain):
 72             bestInfoGain = infoGain_i
 73             bestFeature = i
 74     return bestFeature
 75 
 76 '''
 77 輸入:子數據集的類別標簽列
 78 功能:找出該數據集個數最多的類別
 79 輸出:子數據集中個數最多的類別標簽
 80 '''  
 81 def mostClass(ClassList):
 82     classCount = {}
 83     for class_i in ClassList:
 84         if class_i not in classCount.keys():
 85             classCount[class_i] = 0
 86         classCount[class_i] += 1
 87     sortedClassCount = sorted(classCount.iteritems(),
 88     key=operator.itemgetter(1),reverse = True)        
 89     return sortedClassCount[0][0]
 90 
 91 '''
 92 輸入:數據集,特征標簽
 93 功能:創建決策樹(直觀的理解就是利用上述函數創建一個樹形結構)
 94 輸出:決策樹(用嵌套的字典表示)
 95 '''    
 96 def creatTree(dataset,labels):
 97     classList = [example[-1] for example in dataset]
 98     #判斷傳入的dataset中是否只有一種類別,是,返回該類別
 99     if classList.count(classList[0]) == len(classList):    
100         return classList[0]
101     #判斷是否遍歷完所有的特征,是,返回個數最多的類別
102     if len(dataset[0]) == 1:
103         return mostClass(classList)
104     #找出最好的特征划分數據集
105     bestFeat = BestFeatToGetSubdataset(dataset)
106     #找出最好特征對應的標簽
107     bestFeatLabel = labels[bestFeat]
108     #搭建樹結構
109     myTree = {bestFeatLabel:{}}
110     del (labels[bestFeat])
111     #抽取最好特征的可能取值集合
112     bestFeatValues = [example[bestFeat] for example in dataset]
113     uniqueBestFeatValues = set(bestFeatValues)
114     for value in uniqueBestFeatValues:
115         #取出在該最好特征的value取值下的子數據集和子標簽列表
116         subDataset = getSubDataset(dataset,bestFeat,value)
117         subLabels = labels[:]
118         #遞歸創建子樹
119         myTree[bestFeatLabel][value] = creatTree(subDataset,subLabels)
120     return myTree
121 
122 '''
123 輸入:測試特征數據
124 功能:調用訓練決策樹對測試數據打上類別標簽
125 輸出:測試特征數據所屬類別
126 '''        
127 def classify(inputTree,featlabels,testFeatValue):
128     firstStr = inputTree.keys()[0]
129     secondDict = inputTree[firstStr]
130     featIndex = featlabels.index(firstStr)
131     for firstStr_value in secondDict.keys():
132         if testFeatValue[featIndex] == firstStr_value:
133             if type(secondDict[firstStr_value]).__name__ == 'dict':
134                 classLabel = classify(secondDict[firstStr_value],featlabels,testFeatValue)
135             else: classLabel = secondDict[firstStr_value]
136     return classLabel    
137 
138 
139 '''
140 輸入:訓練樹,存儲的文件名
141 功能:訓練樹的存儲
142 輸出:
143 '''
144 def storeTree(trainTree,filename):
145 
146     fw = open(filename,'w')
147     pickle.dump(trainTree,fw)
148     fw.close()
149 def grabTree(filename):
150 
151     fr = open(filename)
152     return pickle.load(fr)
153 
154 
155 if __name__ == '__main__':
156     dataset,labels = creatDataSet()
157     storelabels = labels[:]#復制label
158     trainTree = creatTree(dataset,labels)    
159     classlabel = classify(trainTree,storelabels,[0,1])
160     print classlabel

 

 

本文來自於:

ID3決策樹的算法原理與python實現

謝謝博主

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM