決策樹算法一:hunt算法,信息增益(ID3)


決策樹入門

決策樹是分類算法中最重要的算法,重點

決策樹算法在電信營業中怎么工作?

 

這個工人也是流失的,在外網轉移比處雖然沒有特征來判斷,但是在此節點處流失率有三個分支概率更大

為什么叫決策樹?
  因為樹的葉子節點是我們最終預判的結果。
決策樹如何來?
  根據訓練樣本建立。
問題1:為什么費用變換率放第一個?
  根據特征建決策樹,會有n棵樹,找出最優樹。
問題2:當我們特征是連續值的時候,到底從哪里開始切分?
  連續值要改為離散的。
問題3:決策樹能不能做回歸

決策樹例子:

不同的決策樹對我們判定的效率,速度有影響。

總結:

樹的深度:深度的基數是1,上圖深度是4。一棵樹所有層次的最大值稱為深度。

決策樹進階

 

**決策樹一共有五種算法。**前面四個都是有關聯的。

Hunt算法:

其中所說的類別是輸出的情況

屬性即每一個樣本的多種特征(如年齡、性別等)

以一個例子一一解說hunt算法過程

 2、3、4行的解釋,分兩種情況

情況一(決策樹剛從根節點出發):假設上面圖買電腦這一列全是是,則是這一個類是葉節點也是根節點

情景二(決策樹正在內部節點分支過程中):上面圖買電腦這一列不全是是,是否混雜,在從根節點,子節點,子節點的子節點的分支過程中,某一分支處的特征(年齡、收入以及學生特征都以作為節點,假設學生開始分支,信用特征作為分支節點時),不論特征的情況如何(即不論信用的好壞)買電腦的情況都是是,則是這一個類作為學生的分支節點

5、6行的解釋

情況一(A = 空):在從根節點,子節點,子節點的子節點的分支過程中,某一分支處的特征(年齡、收入、學生特征以及信用特征都已經作為划分時(假如分到信用特征這一節點處繼續向下划分))沒有時,類的情況還是混雜的(買電腦的情況還是買與不買的都有),則此分支作為葉節點,且類別為這些混雜中類別最多的那一類。如下圖sal<25的分支處(這里<25買房情況相同分支的葉節點可以是0也可以是1,最終選擇為1是應為>25的另外一個分支上是0)

 情景二(D中的樣本在A上的取值相同):在從根節點,子節點,子節點的子節點的分支過程中,某一分支處的特征(年齡、收入、學生特征以及信用特征都已經作為划分時(假如分到信用特征這一節點處繼續向下划分)),但是信用這一節點的取值都相同(就像上圖中假設30、32、33、sal的值都是3000時,右側繼續划分),則此分支作為葉節點,且類別為這些混雜中類別最多的那一類

8-12行的解釋

a*為屬性,a*v為屬性分支時的划分點(離散型的屬性如性別可以划分男女,連續性的屬性例如年齡可以以范圍划分),例如下圖的例子,(對應11、12行解釋)年齡以80划分時大於80的分支為空,則此分支作為葉節點,且類別時這些樣本集類別最多的那一類。線面18-34樣本集中最多的類是0。

14行解釋:

循環遞歸重復1-14行

總結:

決策樹是一個遞歸的過程。
2,3解釋:當所有的樣本點都屬於同一個類別的時候,不需要划分(遞歸結束的一個條件);
5,6解釋:屬性不能再划分的時候,其類別標記取決於該樣本中數據最多的類。如果類別數量相同,注意看一下另一個葉子節點,不能與上一個葉子節點的類別相同,否則,無需划分。
8,解釋:如何構建最優決策樹。
hunt算法有一個bug:不好選最優划分屬性。D是樣本集。
9~14解釋:對於某一個特征(屬性),的每一個值,設置為node並生成一個分支;形成兩個樣本子集。為空,分支節點為葉子節點,否則,樣本子集中數量多的類為返回值。

信息增益–information gain(ID3)

在這里插入圖片描述在這里插入圖片描述

(b)方法更好。
ID3算法主要針對屬性選擇問題
使用信息增益度選擇測試屬性。

決策樹屬於遞歸樹。

信息熵:信息的度量,量化信息的作用。信息熵越小則已知的信息就越多

不確定性的多少就是未知的信息量多少

信息熵衡量的公式:

  數據集D中m個不同的分類,表示以輸出結果的分類(例如上面電信運營案例中的流失情況就是輸出結果,流失與不流失是數據集分類;下面買電腦的情況就是輸出結果,買與不買是數據集分類情況);

  Ci,D表示數據集D中Ci類的集合(例如下面買電腦情況,買這一類有5個,沒買這一類有9個)

計算信息熵例子:

0~100%,先變大,后變小。50%的時候最大。熵為1的時候,不確性最大。熵為0,數據最純。

條件信息熵

如何理解下面圖片的第一句話

  屬性A表示每個樣本中的特征(年齡、性別、收入等),v個不同的取值就是如何去划分屬性A中的每一個特征(以上面買電腦情況來說明,年齡以<30,30-40,>40划分三類,性別以男女划分兩類。。。);

  根據每一個特征求得的信息熵越小就是最優的划分屬性(即hunt中沒有說明如何找出最優屬性的方法)。即某條件下的信息熵越小,信息量越小,以此條件對於數據集的划分越容易得到最終結果。

Info(Dj)樣本子集的信息熵;假設Dj為年齡划分的樣本子集,Info(Dj)表示年齡以<30 / 30-40 / >40的信息熵

信息增益=樣本集的信息熵-某屬性的信息熵
選擇信息增益最大的屬性。

(按條件進行划分的信息熵)例子

按年齡來划分:(年齡的信息增益最大)

 

實現ID3算法:

import numpy as np import operator def creatDataSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true   輸出表示玩不玩,N/Y """ dataSet = np.array([[0, 0, 0, 0, 'N'], [0, 0, 0, 1, 'N'], [1, 0, 0, 0, 'Y'], [2, 1, 0, 0, 'Y'], [2, 2, 1, 0, 'Y'], [2, 2, 1, 1, 'N'], [1, 2, 1, 1, 'Y']]) labels = np.array(['outlook', 'temperature', 'humidity', 'windy']) return dataSet, labels def createTestSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true """ testSet = np.array([[0, 1, 0, 0], [0, 2, 1, 0], [2, 1, 1, 0], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 0], [2, 1, 0, 1]]) return testSet def dataset_entropy(dataset): """ 計算數據集的信息熵 """ classLabel=dataset[:,-1] labelCount={} for i in range(classLabel.size): label=classLabel[i] labelCount[label]=labelCount.get(label,0)+1     #將所有的類別都計算出來了
    #熵值(第一步)
    cnt=0 for k,v in labelCount.items(): cnt += -v/classLabel.size*np.log2(v/classLabel.size) return cnt #接下來切分,然后算最優屬性
def splitDataSet(dataset, featureIndex): #划分后的子集
    subdataset=[] featureValues = dataset[:,featureIndex] featureSet = list(set(featureValues)) for i in range(len(featureSet)): newset=[] for j in range(dataset.shape[0]): if featureSet[i] == featureValues[j]: newset.append(dataset[j,:]) newset=np.delete(newset,featureIndex,axis=1) # newset = newset[:,0:featureIndex].extend(newset[:,featureIndex+1:]) #不包括當前的列,得到新的數據集(數組的處理方式) 
 subdataset.append(np.array(newset)) return subdataset  #划分得到三個子集

def splitDataSetByValue(dataset,featureIndex,value): subdataset=[] #迭代所有的樣本
    for example in dataset: if example[featureIndex]==value: subdataset.append(example) return np.delete(subdataset,featureIndex,axis=1) def chooseBestFeature(dataset,labels): """ 選擇最優特征,但是特征是不包括名稱的。 如何選擇最優特征:每一個特征計算,信息增益最大==條件熵最小就可以。 """
    #特征的個數
    featureNum=labels.size #設置最小熵值
    minEntropy,bestFeatureIndex=1,None #樣本總數
    n=dataset.shape[0] for i in range(featureNum): #指定特征的條件熵
        featureEntropy=0 #返回第i個特征的所有子集
        allSubDataSet=splitDataSet(dataset,i) for subDataSet in allSubDataSet: featureEntropy += subDataSet.shape[0]/n*dataset_entropy(subDataSet) #表示第i個特征的條件熵
        if minEntropy > featureEntropy: #將最小的條件上賦給minEntropy,特征索引值i給bestFeatureIndex
            minEntropy=featureEntropy bestFeatureIndex=i return bestFeatureIndex #最佳增益

def mayorClass(classList): labelCount={} #建立字典類型用於標簽熟練存儲
    for i in range(classList.size): label=classList[i] labelCount[label]=labelCount.get(label,0)+1 #計算每個標簽的數量
    sortedLabel=sorted(labelCount.items(),key=operator.itemgetter(1),reverse=True) return sortedLabel[0][0] def createTree(dataset,labels): """ 參考hunt算法那張圖片 """ classList=dataset[:,-1] if len(set(dataset[:,-1]))==1: return dataset[:,-1][0] #返回類別
    if labels.size==0 or len(dataset[0])==1:  #條件熵最少的一定是類別最多的
        #條件熵算不下去的時候,
        return mayorClass(classList) bestFeatureIndex=chooseBestFeature(dataset,labels) bestFeature=labels[bestFeatureIndex] dtree={bestFeature:{}}  #用代碼表示這棵樹
    featureList=dataset[:,bestFeatureIndex] featureValues=set(featureList) #得到最優節點的划分情況
    for value in featureValues: subdataset=splitDataSetByValue(dataset,bestFeatureIndex,value) sublabels=np.delete(labels,bestFeatureIndex) #將最優節點的標簽刪去后的標簽組
        dtree[bestFeature][value]=createTree(subdataset,sublabels) #將原始的labels干掉一列后的
    return dtree                                                   #數據集和標簽,開始遞歸

if __name__ == "__main__": dataset,labels=creatDataSet() # print(dataset_entropy(dataset)
    # s=splitDataSet(dataset,0)
    # for item in s:
    # print(item)
    print(createTree(dataset,labels))
·····················································
輸出:
{'outlook': {'2': {'windy': {'0': 'Y', '1': 'N'}}, '0': 'N', '1': 'Y'}}

 

if labels.size==0 or len(dataset[0])==1:  #條件熵最少的一定是類別最多的
   #條件熵算不下去的時候,
   return mayorClass(classList) """ 這兩種情況分別是 ['N','N','Y'] ['N'] """

 

labels.size == 0的情況

len(dateset[0]) == 1的情況

 

代碼解釋:
切分子集是為了,計算每一個特征的條件熵,然后選出最優特征。

總結:
決策樹里面的重要的公式:
1,數據集的信息熵公式:Info(D)
2,指定條件下的信息熵:Info_A(D)

將算法優化:
將splitDataSet()和splitDataSetByValue()合二為一。

import numpy as np import operator def creatDataSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true """
dataSet = np.array([[0, 0, 0, 0, 'N'], [0, 0, 0, 1, 'N'], [1, 0, 0, 0, 'Y'], [2, 1, 0, 0, 'Y'], [2, 2, 1, 0, 'Y'], [2, 2, 1, 1, 'N'], [1, 2, 1, 1, 'Y']]) labels = np.array(['outlook', 'temperature', 'humidity', 'windy']) return dataSet, labels
def createTestSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true """ testSet = np.array([[0, 1, 0, 0], [0, 2, 1, 0], [2, 1, 1, 0], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 0], [2, 1, 0, 1]]) return testSet def dataset_entropy(dataset): """ 計算數據集的信息熵 """ classLabel=dataset[:,-1] labelCount={} for i in range(classLabel.size): label=classLabel[i] labelCount[label]=labelCount.get(label,0)+1 #將所有的類別都計算出來了 #熵值(第一步) cnt=0 for k,v in labelCount.items(): cnt += -v/classLabel.size*np.log2(v/classLabel.size) return cnt #接下來切分,然后算最優屬性 def splitDataSet(dataset,featureIndex,value): subdataset=[] #迭代所有的樣本 for example in dataset: if example[featureIndex]==value: subdataset.append(example) return np.delete(subdataset,featureIndex,axis=1) def chooseBestFeature(dataset,labels): """ 選擇最優特征,但是特征是不包括名稱的。 如何選擇最優特征:每一個特征計算,信息增益最大==條件熵最小就可以。 """ #特征的個數 featureNum=labels.size #設置最小熵值 minEntropy,bestFeatureIndex=1,None #樣本總數 n=dataset.shape[0] for i in range(featureNum): #指定特征的條件熵 featureEntropy=0 #返回所有子集 featureList=dataset[:,i] featureValues=set(featureList) for value in featureValues: subDataSet=splitDataSet(dataset,i,value) featureEntropy += subDataSet.shape[0]/n*dataset_entropy(subDataSet) #一個的條件熵 if minEntropy > featureEntropy: minEntropy=featureEntropy bestFeatureIndex=i return bestFeatureIndex #最佳增益 def mayorClass(classList): labelCount={} for i in range(classList.size): label=classList[i] labelCount[label]=labelCount.get(label,0)+1 sortedLabel=sorted(labelCount.items(),key=operator.itemgetter(1),reverse=True) return sortedLabel[0][0] def createTree(dataset,labels): """ 參考hunt算法那張圖片 """ classList=dataset[:,-1] if len(set(dataset[:,-1]))==1: return dataset[:,-1][0] #返回類別 if labels.size==0 or len(dataset[0])==1: #條件熵最少的一定是類別最多的 #條件熵算不下去的時候, return mayorClass(classList) bestFeatureIndex=chooseBestFeature(dataset,labels) bestFeature=labels[bestFeatureIndex] dtree={bestFeature:{}} #用代碼表示這棵樹 featureList=dataset[:,bestFeatureIndex] featureValues=set(featureList) for value in featureValues: subdataset=splitDataSet(dataset,bestFeatureIndex,value) sublabels=np.delete(labels,bestFeatureIndex) dtree[bestFeature][value]=createTree(subdataset,sublabels) #將原始的labels干掉一列 return dtree if __name__ == "__main__": dataset,labels=creatDataSet() # print(dataset_entropy(dataset) # s=splitDataSet(dataset,0) # for item in s: # print(item) print(createTree(dataset,labels)) ······················································· 輸出結果: {'outlook': {'1': 'Y', '0': 'N', '2': {'windy': {'1': 'N', '0': 'Y'}}}}

 

import numpy as np import operator def creatDataSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true   輸出表示玩不玩,N/Y """ dataSet = np.array([[0, 0, 0, 0, 'N'], [0, 0, 0, 1, 'N'], [1, 0, 0, 0, 'Y'], [2, 1, 0, 0, 'Y'], [2, 2, 1, 0, 'Y'], [2, 2, 1, 1, 'N'], [1, 2, 1, 1, 'Y']]) labels = np.array(['outlook', 'temperature', 'humidity', 'windy']) return dataSet, labels def createTestSet(): """ outlook-> 0:sunny | 1:overcast | 2:rain temperature-> 0:hot | 1:mild | 2:cool humidity-> 0:high | 1:normal windy-> 0:false | 1:true """ testSet = np.array([[0, 1, 0, 0], [0, 2, 1, 0], [2, 1, 1, 0], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 0], [2, 1, 0, 1]]) return testSet def dataset_entropy(dataset): """ 計算數據集的信息熵 """ classLabel=dataset[:,-1] labelCount={} for i in range(classLabel.size): label=classLabel[i] labelCount[label]=labelCount.get(label,0)+1     #將所有的類別都計算出來了
    #熵值(第一步)
    cnt=0 for k,v in labelCount.items(): cnt += -v/classLabel.size*np.log2(v/classLabel.size) return cnt #接下來切分,然后算最優屬性
def splitDataSet(dataset, featureIndex): #划分后的子集
    subdataset=[] featureValues = dataset[:,featureIndex] featureSet = list(set(featureValues)) for i in range(len(featureSet)): newset=[] for j in range(dataset.shape[0]): if featureSet[i] == featureValues[j]: newset.append(dataset[j,:]) newset=np.delete(newset,featureIndex,axis=1) # newset = newset[:,0:featureIndex].extend(newset[:,featureIndex+1:]) #不包括當前的列,得到新的數據集(數組的處理方式) 
 subdataset.append(np.array(newset)) return subdataset  #划分得到三個子集

def splitDataSetByValue(dataset,featureIndex,value): subdataset=[] #迭代所有的樣本
    for example in dataset: if example[featureIndex]==value: subdataset.append(example) return np.delete(subdataset,featureIndex,axis=1) def chooseBestFeature(dataset,labels): """ 選擇最優特征,但是特征是不包括名稱的。 如何選擇最優特征:每一個特征計算,信息增益最大==條件熵最小就可以。 """
    #特征的個數
    featureNum=labels.size #設置最小熵值
    minEntropy,bestFeatureIndex=1,None #樣本總數
    n=dataset.shape[0] for i in range(featureNum): #指定特征的條件熵
        featureEntropy=0 #返回第i個特征的所有子集
        allSubDataSet=splitDataSet(dataset,i) for subDataSet in allSubDataSet: featureEntropy += subDataSet.shape[0]/n*dataset_entropy(subDataSet) #表示第i個特征的條件熵
        if minEntropy > featureEntropy: #將最小的條件上賦給minEntropy,特征索引值i給bestFeatureIndex
            minEntropy=featureEntropy bestFeatureIndex=i return bestFeatureIndex #最佳增益

def mayorClass(classList): labelCount={} #建立字典類型用於標簽熟練存儲
    for i in range(classList.size): label=classList[i] labelCount[label]=labelCount.get(label,0)+1 #計算每個標簽的數量
    sortedLabel=sorted(labelCount.items(),key=operator.itemgetter(1),reverse=True) return sortedLabel[0][0] ##添加
def predict(tree,labels,testDate): rootName =list(tree.keys())[0] rootValue = tree[rootName] featureIndex = list(labels).index(rootName) classLabel = None for key in rootValue.keys(): #print(key)
        if testDate[featureIndex] == int(key): if type(rootValue[key]).__name__ == "dict": classLabel = predict(rootValue[key], labels, testDate) else: classLabel = rootValue[key] pass
            pass
        pass
    return classLabel ##添加
def predictAll(teree,labels,treeSet): classLabels = [] for i in testSet: classLabels.append(predict(tree,labels,i)) pass
    return classLabels def createTree(dataset,labels): """ 參考hunt算法那張圖片 """ classList=dataset[:,-1] if len(set(dataset[:,-1]))==1: return dataset[:,-1][0] #返回類別
    if labels.size==0 or len(dataset[0])==1:  #條件熵最少的一定是類別最多的
        #條件熵算不下去的時候,
        return mayorClass(classList) bestFeatureIndex=chooseBestFeature(dataset,labels) bestFeature=labels[bestFeatureIndex] dtree={bestFeature:{}}  #用代碼表示這棵樹
    featureList=dataset[:,bestFeatureIndex] featureValues=set(featureList) #得到最優節點的划分情況
    for value in featureValues: subdataset=splitDataSetByValue(dataset,bestFeatureIndex,value) sublabels=np.delete(labels,bestFeatureIndex) #將最優節點的標簽刪去后的標簽組
        dtree[bestFeature][value]=createTree(subdataset,sublabels) #將原始的labels干掉一列后的
    return dtree                                                   #數據集和標簽,開始遞歸

if __name__ == "__main__": dataset,labels=creatDataSet() # print(dataset_entropy(dataset)
    # s=splitDataSet(dataset,0)
    # for item in s:
    # print(item)
    tree = createTree(dataset,labels) testSet = createTestSet() print(predictAll(tree, labels, testSet))#測試

""" 結果 ['N', 'N', 'Y', 'N', 'Y', 'Y', 'N'] """

 


免責聲明!

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



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