1 演算法概述
1.1 結構分析
決策樹是一種依託決策而建立起來的樹,其中,每乙個內部節點表示乙個屬性上的測試,每乙個分支代表乙個測試的結果輸出,每乙個葉子代表一種類別。
如上圖所示就是乙個決策樹,首先分析所給資料集是否為同一類別,如果是,那就不用劃分了,如果不是,就尋找劃分資料集最好的特徵進行劃分(也就是影響資料集劃分因素最明顯的特徵劃分,這個後面會專門介紹最大資訊增益法劃分,知道怎麼用就中),比如上圖一開始就是選擇的是:傳送郵件網域名稱位址為某某莫,每個內部節點(資料子集)代表乙個二分類問題,每個葉子節點是分類的結果,遇到內部節點就一直劃分,直到劃分的資料子集都屬於同一型別的資料時,就停止劃分,此時,也就意味著你的決策樹已經建好。
1.2 演算法思想
這是一種尋找資料集內部之間規律的演算法,以資訊熵為度量,構造一顆熵值下降最快的數,到葉子節點處的熵值為零。此時,每乙個葉子代表乙個類別。
在決策樹的每乙個非葉子結點劃分之前,先計算每乙個屬性所帶來的資訊增益,選擇最大資訊增益的屬性來劃分,因為資訊增益越大,區分樣本的能力就越強,越具有代表性,很顯然這是一種自頂向下的貪心策略。以上就是id3演算法的核心思想
1.3 演算法實現步驟
①計算每種特徵劃分方式的資訊熵,選取資訊熵最大的一種劃分方式
②遞迴的構建決策樹
2 實現
(1)創造資料集
(2)計算資料集資訊熵
def
calcshannonent
(dataset):
numentries = len(dataset) #len()是計算變數長度的函式 ,numentries=5
labelcounts = {} #為所有可能分類創造字典
#遍歷每條資料集樣本,如果字典裡沒有資料集中的類別,將此類別存入字典中,如果有,將此類別數目加1
#以下for迴圈裡計算結果為labelcounts=['yes':2,'no':3]
#其實,以下for迴圈可以用一句話概括:
#labelcounts[currentlabel]=labelcounts.get(currentlabel,0)+1
for featvec in dataset: #the the number of unique elements and their occurance
currentlabel = featvec[-1]
if currentlabel not
in labelcounts.keys():
labelcounts[currentlabel] = 0
labelcounts[currentlabel] += 1
#計算熵值
shannonent = 0.0
for key in labelcounts: #遍歷上面生成的字典中的每乙個特徵類別,計算其中每個類別的熵值
prob = float(labelcounts[key])/numentries #numentries=5
shannonent -= prob * log(prob,2) #log base 2
return shannonent
(3)根據上面計算的資訊熵,劃分資料集
(4)選擇最好的劃分結果
def
choosebestfeaturetosplit
(dataset):
numfeatures = len(dataset[0]) - 1
#特徵數,-1是因為dataset最後一列是標籤類別
baseentropy = calcshannonent(dataset) #計算總資料集的資訊熵
bestinfogain = 0.0; bestfeature = -1
for i in range(numfeatures): #遍歷每乙個特徵
featlist = [example[i] for example in dataset]#遍歷每個特徵的資料集
uniquevals = set(featlist) #第i個特徵取值集合,如果i=1,則uniquevals=[1,1,1,0,0]
newentropy = 0.0
for value in uniquevals: #依據特徵劃分資料集,並計算每種劃分方式的資訊熵
subdataset = splitdataset(dataset, i, value)
prob = len(subdataset)/float(len(dataset))
newentropy += prob * calcshannonent(subdataset)
infogain = baseentropy - newentropy #calculate the info gain; ie reduction in entropy
if (infogain > bestinfogain): #選擇最大資訊熵的劃分結果
bestinfogain = infogain #if better than current best, set to best
bestfeature = i
return bestfeature #returns an integer
(5)遞迴構造決策樹
多數表決的方法決定葉子節點的分類 –該葉子屬於哪一類的樣本最多,我們就說該葉子屬於哪類
def
createtree
(dataset,labels):
classlist = [example[-1] for example in dataset] #資料集所有標籤列表
#終止條件1;類別完全相同,表示就只有乙個類別,則停止繼續劃分 返回標籤-葉子節點
if classlist.count(classlist[0]) == len(classlist):
return classlist[0]#stop splitting when all of the classes are equal
#終止條件2:無法將資料集劃分成唯一類別時,採用多數表決法決定葉子的分類
if len(dataset[0]) == 1: #stop splitting when there are no more features in dataset
return majoritycnt(classlist) #遍歷完所有的特徵時返回出現次數最多的
#開始建立樹
bestfeat = choosebestfeaturetosplit(dataset) #選擇最好的方式進行劃分資料集,得到最好劃分資料集特徵
bestfeatlabel = labels[bestfeat]
mytree = } #用上面得到的最好劃分資料集特徵建立乙個空樹(空字典)
del(labels[bestfeat]) #刪除labels[bestfeat]
featvalues = [example[bestfeat] for example in dataset]
uniquevals = set(featvalues)
for value in uniquevals: #遍歷當前選擇的特徵包含的所有屬性
sublabels = labels[:] #copy all of labels, so trees don't mess up existing labels
#遞迴呼叫構建樹的過程,直到遍歷完所有劃分資料集屬性,所有相同類別的資料均被分到同乙個資料子集中
mytree[bestfeatlabel][value] = createtree(splitdataset(dataset, bestfeat, value),sublabels)
return mytree
(6)用決策樹進行**標籤
def
classify
(inputtree,featlabels,testvec):
firststr = inputtree.keys()[0] #第乙個特徵屬性:firststr='no su***cing'
#除去第乙個特徵屬性的字典:seconddict=}}
seconddict = inputtree[firststr]
featindex = featlabels.index(firststr) #尋找第乙個特徵屬性在特徵屬性列表中的位置:featindex=0
for key in seconddict.keys(): #遍歷整棵樹,比較待測特徵與樹節點的值,直到找到特徵值完全匹配的葉子節點
if testvec[featindex] == key:
if type(seconddict[key]).__name__ == 'dict':
classlabel = classify(seconddict[key], featlabels, testvec)
else: classlabel = seconddict[key]
return classlabel
機器學習實戰之決策樹
1.熵 entropy h s 用來測量乙個資料集s的不確定程度。h s x x p x log2 p x s 待計算熵的資料集,在id3演算法的每次迭代中會改變 x s中類別的集合 p x 屬於類別x的元素站集合s中總元素的比例 h s 0 集合s 被完全分到乙個類中。在id3中,對每乙個屬性熵,...
機器學習實戰之決策樹
在 機器學習實戰 決策樹這一章的時候,有些地方的 有點看不太懂,看了幾篇部落格,還是未解。最後仔細看書,發現自己不懂資料集的組織方式。希望大家看的時候也注意一下。在決策樹函式呼叫的資料要滿足如下要求 1 資料必須是由列表元素組成的列表,所有的列表元素都要具有相同的資料長度 2 資料 也就是資料集中的...
機器學習實戰 決策樹
決策樹 2 python語言在函式中傳遞的是列表的引用,在函式內部對列表物件的修改,將會影響該列表物件的整個生存週期。為了消除這個不良影響,我們需要在函式的開始宣告乙個新列表物件。在本節中,指的是在劃分資料集函式中,傳遞的引數dataset列表的引用,為了不影響dataset我們重新宣告了乙個ret...