1.决策树的概念
决策树是一种基本的分类与回归方法,通过建立一棵树来对数据进行分类,是定义在空间上的条件概率分布,每一个叶子节点表示类别或数值。
2.决策树的建立
决策树算法需要一个已标记的数据集,其中包含输入特征和相应的目标变量。从根节点开始,决策树算法通过选择最优特征进行数据划分,直到满足停止条件。在预测阶段,给定新的输入数据,决策树会从根节点开始,沿着各个分支路径进行预测,直到到达叶节点。叶节点的类别就是决策结果。最后,可以使用测试数据集评估模型的性能。
3.决策树的特点
决策树的优点是易于理解和解释,能够处理连续和离散的特征,并且对数据集的大小和维度具有较强的适应性。
决策树的些缺点,容易过拟合,尤其是当决策树深度过大时;对噪声敏感,容易在含有噪声的数据集上表现不佳;以及可能产生偏向的分类结果,即对于少数类别的样本可能不够重视。
4.决策树的实现
建立数据集
def creatDataSet():
# 数据集
dataSet=[]
#分类属性,根据自己的数据定义
labels=[' ',' ',' ',' ']
#返回数据集和分类属性
return dataSet,labels
4.1.决策过程-特征选取
决策过程需要找出合适的特征来进行数据分类,可以使用信息的熵来决定选取的特征
n为分类的数目
p(xi)为选择该分类的概率
熵越大,数据的不确定性越大,在决策过程中,需要尽量的减少熵的值。
def entropy(labels):
counter = Counter(labels)
ent = 0.0
for num in counter.values():
p = num / len(labels)
ent += -p * math.log2(p)
return ent
4.2.划分数据集
在决策树算法中,通常使用信息增益或信息增益比来决定哪个特征和哪个阈值是最好的分割点
分割数据集
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
print("第%d个特征的增益为%.3f" % (i, infoGain))
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
4.3决策树的构建
创建字典classCount
来存储每个元素的出现次数。然后,遍历classList
中的每个元素,如果元素不在classCount
中,就添加到classCount
并设置计数为0,然后增加计数。使用sorted
函数将classCount
中的条目按照出现次数进行降序排列。使用lambda
函数作为排序的关键字,让每个条目被排序为(key, value)
对。最后,返回出现次数最多的元素(排序后的第一个元素的键)。
def majorityCnt(classList):
classCount = {}
# 统计classList中每个元素出现的次数
for vote in classList:
if vote not in classCount:
classCount[vote] = 0
classCount[vote] += 1
# 根据字典的值降序排列,返回出现次数最多的元素
sortedClassCount = sorted(classCount.items(), key=lambda x: x[1], reverse=True)
return sortedClassCount[0][0]
创建一个空的子树,然后对于最优特征的每一个值,都递归地调用createTree
函数,并将分割后的数据集作为参数,得到了一个完整的决策树
def createTree(dataSet, labels, featLabels):
# 取分类标签
classList = [example[-1] for example in dataSet]
# 如果类别完全相同,则停止继续划分
if classList.count(classList[0]) == len(classList):
return classList[0]
# 遍历完所有特征时返回出现次数最多的类标签
if len(dataSet[0]) == 1:
return majorityCnt(classList)
# 选择最优特征
bestFeat = chooseBestFeatureToSplit(dataSet)
# 最优特征的标签
bestFeatLabel = labels[bestFeat]
featLabels.append(bestFeatLabel)
# 根据最优特征的标签生成树
myTree = {bestFeatLabel: {}}
# 删除已经使用的特征标签
del(labels[bestFeat])
# 得到训练集中所有最优特征的属性值
featValues = [example[bestFeat] for example in dataSet]
# 去掉重复的属性值
uniqueVls = set(featValues)
myTree[bestFeatLabel] = {}
for value in uniqueVls:
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), labels, featLabels)
return myTree
5.总结
在决策树基于特征对实例进行分类的时候,可以认为是if-else的集合,对不同的特征进行分类。在遇到剩余的实例中所有特征相同时进行剪枝去除贡献较小的节点来减少树的复杂度,避免出现过度拟合和欠拟合的问题。决策树具有直观易懂的特点,可以用于解释一些简单的分类和回归问题。