目录
概念
决策树(decision tree):是一种基本的分类与回归方法,这里讨论的的是分类的决策树。决策树分类是指从根节点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子节点,此时每个子节点对应着该特征的一个取值,如此递归的对实例进行测试并分配,直到到达叶节点,最后将实例分到叶节点的类中。
- 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据
- 缺点:可能会产生过度匹配问题
- 适用数据类型:数值型和标称型
构建决策树:特征选择、决策树的生成、决策树的修建
- 构建根节点,将所有训练数据都放在根节点,选择一个最优特征,按着这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。
- 如果这些子集已经能够被基本正确分类,那么构建叶节点,并将这些子集分到所对应的叶节点去。
- 如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点,如果递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止。
- 每个子集都被分到叶节点上,即都有了明确的类,这样就生成了一颗决策树。
决策树停止划分的条件:
- 类别完全相同则停止划分;
- 无特征可分(这种方式容易过拟合);即使无特征可分,仍不能将数据集划分成仅包含唯一类别的分组,所以挑选出现次数最多的类别作为返回值。
- 设定阈值:某个特征的(内部结点)的信息增益小于一定的阈值。
信息增益
信息熵
- 表示多个类别中的第i个类别,表示数据集中类别为的数据在数据集中出现的概率,假设共有n个类别,...,,信息熵Ent(X)的定义如下
从公式中可以看出,如果概率是0或1时,熵就是0,不确定性是最低的。熵越大,不确定性就越高。
条件熵
- 条件熵Ent(X|A)表示特征A为某个值的条件下,类别为X的熵
信息增益(ID3)
信息增益 = 信息熵 - 条件熵
特征A对数据集D的信息增益记为Gain(X,A),公式为:
例子:X1、X2都是属性
样本 | X1 | X2 | 分类 |
1 | T | T | + |
2 | T | T | + |
3 | T | F | - |
4 | F | F | + |
5 | F | T | - |
6 | F | T | - |
计算已知A事件为X1下的信息增益(只看当前特征值与分类结果)
0.082>0,因此选X1为第一个特征
信息增益率(C4.5)
基尼指数
构建决策树实例
1.ID3
根据公式算法得出一个数据集的信息熵
def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key]) / numEntries
shannonEnt -= prob * log(prob, 2)
return shannonEnt
通过ID3算法选择信息增益最大的特征,结果返回信息增益的最大索引
def splitdataSet(dataSet, axis, value): # 分类数据
retdataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis + 1:])
# 去掉对应位置的特征
retdataSet.append(reducedFeatVec)
return retdataSet
def chooseBestFeatureToSplit(dataSet): # 选择信息增益最大的特征
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures):
featList = [example[i] for example in dataSet]
uniqueVals = set(featList)
newEntropy = 0.0
for value in uniqueVals:
subdataSet = splitdataSet(dataSet, i, value)
prob = len(subdataSet) / float(len(dataSet))
newEntropy += prob * calcShannonEnt(subdataSet)
infoGain = baseEntropy - newEntropy
if infoGain > bestInfoGain:
bestInfoGain = infoGain
bestFeature = i
return bestFeature
导入数据集,取数据集中的偶数项作为训练集,取奇数项作为测试集
def file_train(filename): # 取数据集偶数作为训练集
fr = open(filename)
lines = fr.readlines()
res = []
i = 0
for line in lines:
line = line.strip()
temp = line.split(",")
if i % 2 == 0: # 取总数据集里的偶数
res.append(temp)
i += 1
labels = ["top-left-square", "top-middle-square", "top-right-square",
"middle-left-square", "middle-middle-square", "middle-right-square",
"bottom-left-square","bottom-middle-square","bottom-right-square"]
return res, labels
def file_test(filename): # 取数据集的奇数作为测试集
fr = open(filename)
lines = fr.readlines()
res = []
i = 0
for line in lines:
line = line.strip()
temp = line.split(",")
if i % 2 == 1: # 取总数据集里的奇数
res.append(temp)
i += 1
labels = ["top-left-square", "top-middle-square", "top-right-square", "middle-left-square", "middle-middle-square", "middle-right-square","bottom-left-square","bottom-middle-square","bottom-right-square"]
return res, labels
生成的决策树
2.基尼指数
def calcProbabilityEnt(dataSet):
numEntries = len(dataSet)
feaCounts = 0
fea1 = dataSet[0][len(dataSet[0])-1]
for feaVec in dataSet:
if feaVec[-1] == fea1:
feaCounts += 1
probabilityEnt = float(feaCounts) / numEntries
return probabilityEnt
#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #特征数量,numfeature为特征的维度,因为最后一列为标签,所以需要减去1
if numFeatures == 1:
return 0
bestGini = 1 #最佳基尼指数
bestFeature = -1 #最优的划分特征初始化为-1
for i in range(numFeatures): #遍历所有的特征
featList = [example[i] for example in dataSet]
feaGini = 0 #定义特征的值的基尼系数
uniqueVals = set(featList)
for value in uniqueVals: #遍历该特征维度下对应的所有特征值
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
probabilityEnt = calcProbabilityEnt(subDataSet)
feaGini += prob * (2 * probabilityEnt * (1 - probabilityEnt))
if (feaGini < bestGini):
bestGini = feaGini
bestFeature = i #记录基尼指数最小的索引值
return bestFeature
总结
ID3算法中,选择的是信息增益来进行特征选择,信息增益大的特征优先选择。基尼指数的意义是从数据集D中随机抽取两个样本类别标识不一致的概率。基尼指数越小,数据集的纯度越高。相比于信息增益,信息增益比等作为特征选择方法,基尼指数省略了对数计算,运算量比较小,也比较容易理解,所以CART树选择使用基尼系数用来做特征选择。在这个模型中用ID3算出的准确率比基尼指数的高一些。