基本概念和公式
- 信息
- 信息熵
度量样本集合纯度最常用的一种指标:
Ent(D)值越小,则D纯度越高 - 信息增益
(信息增益标准对可取数目较多的属性有所偏好) - 信息增益率
(信息增益率标准对可取数目较少的属性有所偏好)
(C4.5采取的策略是,先从候选属性中找出信息增益高于平均值的属性,再从中选择增益率最高的) - 基尼指数
基尼值:
反映从数据集D中随机抽取两个样本,其类别标志不一致的概率
Gini(D)越小,数据集D的纯度越高
属性a的基尼指数:
- 剪枝处理
剪枝处理是对付过拟合的一种方法。
预剪枝:
在决策树生成过程中,对每个节点在划分前后进行估计,若当前节点划分不能带来决策树泛化性能的提升(即:训练集精度提升),则停止划分当前结点,并将当前节点作为叶子节点。
后剪枝:
从训练集中生成一棵完整的决策树,然后对节点(子节点都是叶节点)进行剪枝,若剪枝后决策树的泛化能力比未剪枝前好,则将此节点剪掉,作为叶节点,叶节点的标记为所有包含的样本中个数最多的标记。
两种剪枝方法的比较:
后剪枝保留了更多的分支,欠拟合风险小,但训练时间开销更大。 - 连续值处理
候选划分点集合:
T_a={(ai+a(i+1))/2|1≤i≤n-1}
根据信息增益公式:
计算每个划分集合的点划分出来的信息增益值,然后选择信息增益值最大的点作为最佳划分点。 - 缺失值的处理
样本集在属性a上没有缺失的集合记为,权重Wx。
若样本在属性a上的值缺失,则同时将样本华人与所有子节点,权值设为R*W
决策树的代码实现
- 香农公式的代码实现
from math import log
def calcshannonEnt(dataset):
numData =len(dataset)
featVect = {}
calcshannon = 0.0
for data in dataset:
label =data[-1]
if label not in featVect.keys():
featVect[label] = 0
featVect[label] +=1
for i in featVect.keys():
sublabels =featVect[i]
p = float(sublabels)/numData
calcshannon -= p*log(p, 2)
return calcshannon
- 数据集的代码实现
def createDataSet():
data = [
[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']
]
labels = ['no surfacing', 'flippers']
return data, labels
- 划分数据集
# coding=utf-8
#划分数据集
def splitDataSet(dataset, axis, value):
newDataSet = []
for data in dataset:
feature = data[axis]
if feature == value:
addFeat = data[:axis]
addFeat.extend(data[axis+1:])
newDataSet.append(addFeat)
return newDataSet
- 找最好的特征对数据集进行划分
# coding=utf-8
#信息增益最大即为最好特征
from calcshannonEnt import *
from splitDataSet import *
def chooseBestFeaturetoSplit(dataset):
numFeature = len(dataset[0])-1
baseCalcshannon = calcshannonEnt(dataset)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeature):
numFeatureValue = [example[i] for example in dataset]
uniqueValue = set(numFeatureValue)
currentCalcshannon = 0.0
for value in uniqueValue:
subData = splitDataSet(dataset, i, value)
p = float(len(subData))/len(dataset)
currentCalcshannon += p*calcshannonEnt(subData)
infoGain = baseCalcshannon - currentCalcshannon
if infoGain>bestInfoGain:
bestInfoGain = infoGain
bestFeature = i
return bestFeature
- 构造决策树
# coding=utf-8
"""决策树创建设计递归过程"""
from chooseBestFeaturetoSplit import *
from majority import *
def createTree(dataset,labels):
#递归出口:样本所有分类标签一致,所有特征值考察完毕
labelsValue = [example[-1] for example in dataset]
if labelsValue.count(labelsValue[0]) == len(labelsValue):
return labelsValue[0]
if len(dataset
[0]) == 1:
return majority(dataset)
bestFeature = chooseBestFeaturetoSplit(dataset)
featureLabels = labels[bestFeature]
myTree = {featureLabels: {}}
del(labels[bestFeature])
valueVect = [example[bestFeature] for example in dataset]
uniqueVect = set(valueVect)
for value in uniqueVect:
subLabel = labels[:]
myTree[featureLabels][value] = createTree(splitDataSet(dataset, bestFeature, value), subLabel)
return myTree
确定同一类别中叶节点的标签
import operator
def majority(dataset):
label = [example[-1] for example in dataset]
uniqueLabel = set(label)
labelList = {}
for data in dataset:
subLabel =data[-1]
if subLabel not in labelList:
labelList[subLabel] = 0
labelList[subLabel] +=1
labelCount = sorted(labelList.iteritems(), key=operator.itemgetter(1), reverse=True)
return labelCount[0][0]
- 确定测试数据标签
from createTree import *
def classify(myTree,labels,testVect):
firstStr = myTree.keys()
secondStr = myTree.keys()[0]
labelsIndex = labels.index(firstStr)
for i in secondStr:
subValue = i.keys()
if testVect == subValue:
if subValue.__name__ == 'dict':
classify(subValue,labels,testVect)
else:
return subValue
将决策树程序存储起来
import pickle
def storeTree(tree, filename):
fw = open(filename, 'w')
pickle.dump(tree, fw)
fw.close()
def grapTree(filename):
fr = open(filename)
return pickle.load(fr)
决策树优缺点
优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据
缺点:可能会产生过度匹配