ID3和C4.5决策树算法总结
2016-06-13 12:32
337 查看
1.决策树的算法流程
决策树的算法流程主要是:1.如果当前样本集全部为同一类别,则返回这一类标签
2.如果当前属性集为空集或者D中样本在属性集中的取值全部相同,那么采用多数表决法,返回样本数最多的类标签
3.如果不满足上面三个条件,说明当前结点还可以继续划分,这时候要选择最优的属性
4.选择完属性之后根据属性值划分样本,如果在某个取值下样本集为空,那么标记为父节点中样本最多的类,否则递归产生子节点
5.返回根节点
2.ID3决策树
ID3决策树选择最优属性的方式是选择能使划分后的样本集合信息增益最大的属性假设样本第k类的样本所占的比例是pk,样本一共有C类
信息熵的定义为
Ent(D)=−∑Ck=1pk∗logpk2
假设属性a有V个取值
用属性a划分集合后的信息增益定义为
Gain(D,a)=Ent(D)−∑Vv=1|Dv|/|D|∗Ent(Dv)
选择能使信息增益最大的属性
但是注意到,ID3算法可能对取值较少的属性有所偏好,所以C4.5算法对这点进行了改变。
3.C4.5决策树
C4.5算法使用增益率来衡量属性的优劣,增益率定义为:Gainratio(D,a)=Gain(D,a)/IV(a)
IV(a)=−∑Vv=1|Dv|/|D|∗log|Dv|/|D|2
其中IV(a)称为属性a的固有值,注意到这个固有值的计算公式和信息熵的很类似。
属性a的可能取值数目越多,IV(a)的值通常会越大,这同样带来了一个问题,这可能对属性取值较少的属性有所偏好,所以C4.5算法采用了一个启发式的方案,首先先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
连续值处理
C4.5算法采用二分法对连续属性进行处理,假设当前样本集合在某个连续属性上有n个取值,首先对这n个属性值排序,然后取每两个相邻值的平均值作为划分值来考察。与离散属性不同,若当前结点划分属性为连续属性,那么该属性还可以作为后代结点的划分属性。
缺失值处理
现实中常常遇到不完整样本,也就是样本在某些属性的取值缺失,此时需要解决两个问题:1.如何在属性值缺失的情况下进行属性选择
2.给定划分属性,如何对缺失该属性的样本进行划分
解决这两个问题的方法是给每一个样本一个权值,计算信息增益的时候只选用没有缺失值的样本,选择完属性后,让每一个缺失该属性值的样本以不同的概率进入到每个子节点中,也就是将进入这些子节点的该样本的权值置为不同的值。
4.Python实现
下面是用python实现ID3的代码,没有新定义结点的数据结构,而是使用了内置的dict类型表示非叶结点结点,对于叶子节点用一个字符串(类标签)。对于每一个非叶结点,只有一个键值为当前结点的划分属性,然后是属性值对应的叶子节点。例如:
一棵典型的数的根节点是这个样子的:
{‘a’: {0: ‘no’, 1: {‘b’: {0: ‘no’, 1: ‘yes’}}}}
其中a,b为属性名,0,1为属性值,yes,no为类别名
from numpy import * from math import log import operator # ID3算法 def createDataSet(): dataSet = [[1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 0, 'no']] feature = ['a', 'b'] featureValues = [[0, 1], [0, 1]] return dataSet, feature, featureValues # 计算熵 def calEnt(dataSet): num = len(dataSet) labelCount = {} for data in dataSet: label = data[-1] if label not in labelCount: labelCount[label] = 0 labelCount[label] += 1 ent = 0 for label in labelCount: p = float(labelCount[label])/num ent -= p * log(p, 2) return ent # 划分数据集 def splitByVal(dataSet, axis, val): retDataSet = [] for data in dataSet: if data[axis] == val: newData = data[:axis] newData.extend(data[axis+1:]) retDataSet.append(newData) return retDataSet # 选择划分方式 def chooseBestFeature(dataSet): numFeatures = len(dataSet[0]) - 1 numVector = len(dataSet) baseEnt = calEnt(dataSet) bestInfoGain = 0 bestFeature = -1 for i in range(numFeatures): featureList = [data[i] for data in dataSet] featureList = set(featureList) currentEnt = 0 for feature in featureList: tmpDataSet = splitByVal(dataSet, i, feature) tmpLen = len(tmpDataSet) tmpEnt = calEnt(tmpDataSet) currentEnt += tmpEnt * tmpLen / numVector currentInfoGain = baseEnt - currentEnt if (currentInfoGain > bestInfoGain): bestFeature = i bestInfoGain = currentInfoGain return bestFeature # 找出多数类别 def findMajoritiyClass(dataSet): classCount = {} for data in dataSet: currentClass = data[-1] if currentClass not in classCount.keys(): classCount[currentClass] = 0 else: classCount[currentClass] += 1 sortedClassCount = sorted(classCount.items(), key=lambda d : d[1], reverse=True) return sortedClassCount[0][0] # 建树操作 def createTreeNode(dataSet, labels, featureValues): classList = [example[-1] for example in dataSet] majorityClass = findMajoritiyClass(dataSet) # 如果类别相同,将当前节点标记为这个类别 if classList.count(classList[0]) == len(classList): return classList[0] # 如果当前属性集为空或者样本在属性集中的取值相同 # 采用多数表决的方法将当前节点标记为数量最多的类别 if len(dataSet[0]) == 1 or dataSet.count(dataSet[0]) == len(dataSet): return majorityClass # 其他情况 bestFeature = chooseBestFeature(dataSet) bestFeatureLabel = labels[bestFeature] del(labels[bestFeature]) node = {bestFeatureLabel:{}} for val in featureValues[bestFeature]: subLabels = labels[:] subFeatureValues = featureValues[:bestFeature] subFeatureValues.extend(featureValues[bestFeature+1:]) subDataSet = splitByVal(dataSet, bestFeature, val) #如果子集为空,那么输出父节点多数类的标签 if len(subDataSet) == 0: node[bestFeatureLabel][val] = majorityClass else: node[bestFeatureLabel][val] = createTreeNode(subDataSet, subLabels, subFeatureValues) labels.insert(bestFeature, bestFeatureLabel) return node def classify(node, featureLabels, featureValues, inx): while type(node) is dict: firstFeature = list(node.keys())[0] featureIndex = featureLabels.index(firstFeature) featureValue = inx[featureIndex] node = node[firstFeature][featureValue] return node #自己构造数据集 ,属性集,属性的取值集合 dataSet, labels, featureValues = createDataSet() #构造决策树 root = createTreeNode(dataSet, labels, featureValues) print(root) #分类,最后一个是要预测的向量 classOfX = classify(root, labels, featureValues, [1, 1]) print(classOfX) print(root)
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例