決策樹入門
決策樹是分類算法中最重要的算法,重點
決策樹算法在電信營業中怎么工作?
這個工人也是流失的,在外網轉移比處雖然沒有特征來判斷,但是在此節點處流失率有三個分支概率更大
為什么叫決策樹?
因為樹的葉子節點是我們最終預判的結果。
決策樹如何來?
根據訓練樣本建立。
問題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'] """