您的位置:首页 > 其它

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息