决策树是分类算法中最重要的算法,重点
因为树的叶子节点是我们最终预判的结果。
决策树如何来?
根据训练样本建立。
问题1:为什么费用变换率放第一个?
根据特征建决策树,会有n棵树,找出最优树。
问题2:当我们特征是连续值的时候,到底从哪里开始切分?
连续值要改为离散的。
问题3:决策树能不能做回归
树的深度:深度的基数是1,上图深度是4。一棵树所有层次的最大值称为深度。
决策树是一个递归的过程。
2,3解释:当所有的样本点都属于同一个类别的时候,不需要划分(递归结束的一个条件);
5,6解释:属性不能再划分的时候,其类别标记取决于该样本中数据最多的类。如果类别数量相同,注意看一下另一个叶子节点,不能与上一个叶子节点的类别相同,否则,无需划分。
8,解释:如何构建最优决策树。
hunt算法有一个bug:不好选最优划分属性。D是样本集。
9~14解释:对于某一个特征(属性),的每一个值,设置为node并生成一个分支;形成两个样本子集。为空,分支节点为叶子节点,否则,样本子集中数量多的类为返回值。
(b)方法更好。
ID3算法主要针对属性选择问题
使用信息增益度选择测试属性。
决策树属于递归树。
信息熵:信息的度量,量化信息的作用。
信息量==不确定性的多少。
比特是位。正常都是2为底
当32支球队夺冠概率相同时,信息熵是5比特;否则小于5比特。
计算信息熵小例子:
Cm是指class label
**0~100%,先变大,后变小。50%的时候最大。**熵为1的时候,不确性最大。熵为0,数据最纯。
信息增益=样本集的信息熵-某属性的信息熵
选择信息增益最大的属性。
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):
#划分后的子集
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
#返回所有子集
allSubDataSet=splitDataSet(dataset,i)
for subDataSet in allSubDataSet:
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=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'}}
代码解释:
切分子集是为了,计算每一个特征的条件熵,然后选出最优特征。
决策树里面的重要的公式:
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'}}}}