当前位置:   article > 正文

使用C4.5算法实现决策树(Python)_c4.5决策树图 python

c4.5决策树图 python

使用C4.5算法实现一棵完整的树

决策树的构建需要找到最优特征列对树的节点进行层层划分,而找寻最优特征列常用的有ID3,C4.5,CART三种方法,今天我给大家讲解一下如何使用C4.5算法来找到最优特征列来建立决策树。

1.首先我们创建一组数据,该数据组一共由8组数据组成,共2列特征列,1列标签列

  1. from math import log
  2. import operator
  3. def createDataSet():
  4. dataSet = [[1,1,'yes'],
  5. [1,1,'yes'],
  6. [1,0,'yes'],
  7. [0,1,'no'],
  8. [0,1,'no'],
  9. [0,0,'no'],
  10. [0,0,'yes'],
  11. [0,0,'no']]
  12. labels = ['是否有房产','是否有车']
  13. return dataSet,labels

2.使用ID3算法,需计算信息熵,我们先创建calcShannonEnt方法计算信息熵

注:熵的计算公式为   参照公式理解代码更加简单。

  1. def calcShannonEnt(dataSet):
  2. num = len(dataSet) # 总共有多少行数据 8
  3. shannonEnt = 0.0 #初始化信息熵
  4. labelCounts = {}
  5. for item in dataSet: # 遍历整个数据集,每次取一行
  6. label = item[-1] #取该行最后一列的值 即标签
  7. if label not in labelCounts: # 在字典中这个label是否存在
  8. labelCounts[label] = 0
  9. labelCounts[label] += 1 #{ 'yes':2,'no':3 }
  10. for key in labelCounts:
  11. p = float(labelCounts[key]/num) # 即每个标签所占的比重
  12. #print( p )
  13. shannonEnt -= p * log(p,2) #log base 2 计算信息熵
  14. return shannonEnt # 返回根节点信息熵
  15. # labelCounts {'yes': ..., 'no': ...}

我们来测试一下这个方法

  1. dataSet,labels = createDataSet()
  2. shan = calcShannonEnt( dataSet )
  3. print( shan )
  4. '''
  5. 熵值越高,则混合的数据越多
  6. '''
  7. # 下面再增加一个分类
  8. dataSet[7][-1] = '不确定'
  9. shan = calcShannonEnt( dataSet )
  10. print( shan )

运行上面代码得到结果

3. 接下来,我们创建一个splitDataSet方法来对我们的数据集进行切割

注:实际上就是将每一行的第二列特征列和标签列切分出来,以方便后面的计算

  1. def splitDataSet( dataSet,axis,value ):
  2. result = []
  3. for item in dataSet: # item: [1,1,'yes']
  4. if item[axis] == value:
  5. r = item[:axis] + item[axis+1:] # []+[1,'yes'] => r=> [1,'yes']
  6. # r = item[-1:] #TODO: 只作熵运算的话,只用保留最后一列的值即可
  7. result.append(r)
  8. return result

我们再来测试一下代码,看看其实现效果如何

  1. dataSet,labels = createDataSet()
  2. result = splitDataSet( dataSet,0,1 )
  3. print(result)
  4. result = splitDataSet( dataSet,0,0 )
  5. print(result)
  6. result = splitDataSet( dataSet,1,1 )
  7. print(result)
  8. result = splitDataSet( dataSet,1,0 )
  9. print(result)

运行上面代码得到结果

4. 到了我们最重要的一步,通过信息熵计算信息增益率来求出划分数据集的最优特征

注:信息增益的计算公式为

       信息增益率的计算公式为

       其中  

  1. # 选取当前数据集下,用于划分数据集的最优特征
  2. def chooseBestFeatures(dataSet):
  3. # 1. 特征总数 2
  4. numFeatures = len(dataSet[0]) -1 # 获取当前数据集的特征个数,最后一列是分类标签 2
  5. # 2. 计算信息熵 1
  6. ent = calcShannonEnt(dataSet) # 计算当前数据集的信息熵 (根节点信息熵)
  7. # 3. 最佳信息熵
  8. bestGain = 0.0;
  9. # 4. 最佳特征号 (0,1)
  10. bestFeatureID = -1 # 初始化最优信息增益和最优的特征
  11. # 5.最佳信息增益率
  12. infogain = 0.0;
  13. # 循环特征(列)
  14. for i in range(numFeatures):
  15. list1 = [line[i] for line in dataSet] # 获取数据集中当前特征下的所有值
  16. uniqueValues = set(list1) # 每一列去重后的值, set可以去重 set(list) 将list列表强制转换为set {0,1}
  17. #print( uniqueValues )
  18. newEnt = 0.0 # 条件熵
  19. s = 0.0
  20. for value in uniqueValues:
  21. # 调用splitDataSet ( 列,set中的值 ) -> 得到子集
  22. subDataSet = splitDataSet(dataSet,i,value) # (dataSet,0,0) (dataSet,0,1) (dataSet,1,0) (dataSet,1,1)
  23. # 计算概率
  24. prob = len(subDataSet)/float(len(dataSet)) # 5/8 3/8 4/8 4/8
  25. # 计算熵
  26. newEnt += prob * calcShannonEnt(subDataSet)
  27. s -= prob * log(prob, 2);
  28. print( '信息熵为:' + str(ent) )
  29. print( '第' + str(i) + '列的条件熵为:' + str(newEnt) )
  30. gain = ent - newEnt
  31. print( '第' + str(i) + '列的信息增益为:' + str(gain) )
  32. infogain = gain/s # 求该列的信息增益比
  33. print( '第' + str(i) + '列的信息增益比为:' + str(infogain) )
  34. if (infogain > bestGain):
  35. # 比较每个特征的信息增益比,只要最好的信息增益比
  36. bestGain = infogain
  37. bestFeatureID = i
  38. return bestFeatureID

在代码中,s 即为公式中的 IV(a)

测试一遍上面代码计算信息增益和信息增益率

  1. dataSet,labels = createDataSet()
  2. index = chooseBestFeatures( dataSet )
  3. print(index)

得到结果

5. 建立一个classNum()方法(为构建决策树做准备)

注:该方法实际上就是将传入的离散型数据按出现的频率进行降序排列,并返回第一个键名

  1. def classNum( classList ):
  2. '''
  3. classList: 分类的名称
  4. '''
  5. classCount = {} # 存各种分类出现的频率 : {'yes',1,'no',2}
  6. for label in classList:
  7. classCount[label] = classCount.get(label,0) + 1
  8. # 对字典进行排序
  9. sortedClassCount = sorted( classCount.items(),key=operator.itemgetter(1),reverse=True )
  10. print( sortedClassCount )
  11. return sortedClassCount[0][0]

对此方法进行测试

classNum( ['yes','no','no','yes','no'] )

得到结果

6. 下面我们开始根据我们得到的最优特征来构建决策树

  1. # 生成决策树的总方法
  2. def createTree(dataSet,labels,depth=0,max_features=None,max_depth=None):
  3. # 求出 dataSet 中的样本所属的类别,即递归停止的条件一
  4. # 返回当前数据集下标签所有的值
  5. classList = [example[-1] for example in dataSet] # ['yes','yes','yes','no','no','no','yes','no']
  6. # 终止条件1: 可以加上判断 这个classList是否纯净
  7. if classList.count(classList[0]) == len(classList):
  8. # 纯净的意思就是此数据中所有特征都相等
  9. # 当整个dataSet中的类别完全相同时类别已经纯净了,则停止继续划分,直接返回该类标签
  10. return classList[0]
  11. # 终止条件2: 列中的取值种类 <=max_features 时. max_features 即划分时考虑的最大特征数 默认为 None
  12. if max_features == None:
  13. max_features = 1
  14. if len( dataSet[0] )<=max_features:
  15. return classNum( classList ) # 返回数量多的那一个 标签
  16. # max_depth 树的最大深度,也就是说当树的深度到达max_depth的时候无论还有多少可以分支的特征,决策树都会停止运算
  17. if max_depth!=None:
  18. if depth>=max_depth:
  19. return classNum(classList)
  20. depth = depth + 1
  21. # 获取最好的分类特征索引
  22. # dataSet = [1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'yes'], [0, 1, 'no'], [0, 1, 'no'], [0, 0, 'no'], [0, 0, 'yes'], [0, 0, 'no']
  23. bestFeat = chooseBestFeatures(dataSet) # bestFeat: 0 bestFeat: 0
  24. #print( 'bestFeat:',bestFeat )
  25. # 获取该特征的名字
  26. # labels = ['是否有房产', '是否有车']
  27. bestFeatLabel = labels[bestFeat]
  28. #print( 'bestFeatLabel:',bestFeatLabel ) # bestFeatLabel: 是否有房产 bestFeatLabel: 是否有车
  29. # 这里直接使用字典变量来存储树信息,这对于回执树形图很重要
  30. myTree = {bestFeatLabel:{}} # 当前数据集选取最好的特征存储在bestFeat中
  31. del(labels[bestFeat]) # 删除已经在选取的特征 此时 labels = ['是否有车']
  32. # 取出最优列的值
  33. featValues = [example[bestFeat] for example in dataSet]
  34. # featValues: [1, 1, 1, 0, 0, 0, 0, 0] featValues: [1, 1, 0, 0, 0]
  35. #print( 'featValues:',featValues )
  36. # 去重
  37. uniqueVals = set(featValues) # [1,0]
  38. # 根据这个列的这个 uniqueVals值来切分树的节点
  39. for value in uniqueVals:
  40. # myTree -> 房产 -> 1
  41. # 房产 -> 0
  42. subLabels = labels[:]
  43. #print( 'subLabels:',subLabels )
  44. temp = splitDataSet( dataSet,bestFeat,value )
  45. #print( 'temp:',temp )
  46. myTree[bestFeatLabel][value] = createTree(temp,subLabels,depth=depth,max_features=max_features,max_depth=max_depth)
  47. return myTree

我们来看看我们构建的决策树

 

该决策树共进行两次分类,第一次由‘是否有房产’进行一次划分,第二次由‘是否有车’进行一次划分

由于我们建立的数据并不合理,所以看上去我们建立的决策树并不可观,大家可以试试更多数据构建新的决策树

注:此文章为代码实现,看起来可能有些费解,大家可以参照本人的另一篇博客https://blog.csdn.net/LA401088242/article/details/89034077 了解其原理,以便大家更好的了解代码

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/363895
推荐阅读
相关标签
  

闽ICP备14008679号