决策树知识点及代码

1.1基本流程

决策树(decision tree)是一类常见的的机器学习方法,亦称“判定树”,以二分类任务为例,希望从给定训练数据集学的一个模型用以对新示例进行分类。

大量数据—>模型

一般的,一颗决策树包含一个根结点,若干个内部节点和若干个叶结点;
中间结点是决策过程,叶结点是决策结果。根结点包含样本全集。

决策树学习基本算法(是一个递归算法)为:

决策树知识点及代码_第1张图片

14:从A中去掉a*;

决策树知识点及代码_第2张图片

1.2 划分选择

关键:如何选择最优划分属性。
一般而言,随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的"纯度" (purity)越来越高.

1.2.1信息增益(往最大)

“信息熵” (information entropy)是度量样本集合纯度最常用的一种指标。
假设样本集合为D,则D的信息熵定义为:
决策树知识点及代码_第3张图片

计算信息熵时约定:若p=0,则plog2p=0.
Ent(D)的最小值为0,最大值为log2|m|。

其中样本集合D中第i类样本所占的比例为Pi (i = 1,2,. . . ,|m|)。
Ent(D) 的值越小,则 D 的纯度越高。
给分结点赋予权重|Dv|/|D|,样本数越多的分支结点的影响越大。
用属性a对样本集D进行划分所获得的“信息增益”公式:
决策树知识点及代码_第4张图片
一般来说,一个属性的信息增益越大,就意味着使用该属性来进行划分所得到的“纯度提升”越大。因此,我们可以使用信息增益来进行决策树的第一个结点划分属性选择。(选出决策树的第一个顶头划分的属性,再继续往下划分)

信息熵越小,数据就越纯,信息增益就越大。

1.2.2 增益率

计算下图西瓜数据集中各个属性的信息增益,选取值最大的一个属性作为划分属性。
决策树知识点及代码_第5张图片决策树知识点及代码_第6张图片决策树知识点及代码_第7张图片
决策树知识点及代码_第8张图片
决策树知识点及代码_第9张图片在这里插入图片描述
决策树知识点及代码_第10张图片
信息增益率公式:
决策树知识点及代码_第11张图片
IV(a)称为属性a的“固定值”,属性a的可能取值数目越多(即V越大),则IV(a)的值通常会越大。

启发式:信息增益高——>增益率高

1.2.3 基尼指数(往最小)

一、基尼指数的概念(CART决策树)
基尼指数(Gini不纯度)表示在样本集合中一个随机选中的样本被分错的概率。
注意:Gini指数越小表示集合中被选中的样本被参错的概率越小,也就是说集合的纯度越高,反之,集合越不纯。当集合中所有样本为一个类时,基尼指数为0.

二、基尼系数的计算公式
基尼指数的计算公式为:
决策树知识点及代码_第12张图片
在机器学习中,CART分类树算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(比)相反。

1.3 剪枝处理

剪枝处理(pruning)是决策树学习算法中对付“过拟合”的主要手段, 在决策树学习中, 为了尽可能正确分类训练样本, 节点划分过程不断重复, 有时候会造成决策树分支过多, 以至于将训练样本集自身特点当作泛化特点, 而导致过拟合。 因此可以采用剪枝处理来去掉一些分支来降低过拟合的风险。 剪枝的基本策略有预剪枝(prepruning)和后剪枝(postprunint).
预剪枝是指在决策树生成过程中, 在每个节点划分前先估计其划分后的泛化性能, 如果不能提升, 则停止划分, 将当前节点标记为叶结点。要对划分前后的泛化性能进行评估。
后剪枝是指生成决策树以后,再自下而上对非叶结点进行考察, 若将此节点标记为叶结点可以带来泛化性能提升, 则修改之.

往标记为叶结点方向走

留出法:预留一部分数据用作“验证集”以进行性能评估。
**后剪枝决策树通常比预剪枝决策树保留了更多的分支。**一般情况,后剪枝决策树的欠拟合风险小,泛化能力往往优于预剪枝决策树。但是后剪枝决策树的训练时间更长,首先后剪枝决策树本身就是基于完全决策树上建立的,并且还需要自底向上的对树中地所有非叶子节点进行逐一考察。

代码部分(作业):

from math import log
import operator  # 导入operator模块,提供一套与python的内置运算符对应的高效率函数


def calcShannonEnt(dataSet):
    # 计算数据的熵(entropy)
    numEntries = len(dataSet)  # 数据条数 numEntries = 8
    labelCounts = {
     }
    for featVec in dataSet:
        currentLabel = featVec[-1]  # 每行数据的最后一个字(类别)
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1  # 统计有多少个类以及每个类的数量
    shannonEnt = 0
    for key in labelCounts:
        prob = float(labelCounts[key]) / numEntries  # 计算单个类的熵值 prob 为每个值出现的频率
        shannonEnt -= prob * log(prob, 2)  # 数学公式,计算熵 累加每个类的熵值
    return shannonEnt


def createDataSet1():  # 创造示例数据
    dataSet = [['长', '粗', '男'],
               ['短', '粗', '男'],
               ['短', '粗', '男'],
               ['长', '细', '女'],
               ['短', '细', '女'],
               ['短', '粗', '女'],
               ['长', '粗', '女'],
               ['长', '粗', '女']]
    labels = ['头发', '声音']  # 两个特征
    return dataSet, labels


def splitDataSet(dataSet, axis, value):
    # 按某个特征分类后的数据
    # 查找数据集 dataSet  第 axis 列值== value 的元素,再排除第 axis 列的数据,组成一个新的数据集
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]  # chop out axis used for splitting
            reducedFeatVec.extend(featVec[axis + 1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet


# 该函数使用了三个输入参数:带划分的数据集、划分数据集的特征(数据集第几列)、需要返回的特征的值(按哪个值划分)。
# 函数先选取数据集中第axis个特征值为value的数据,从这部分数据中去除第axis个特征,并返回。


def chooseBestFeatureToSplit(dataSet):  # 选择最优的分类特征
    numFeatures = len(dataSet[0]) - 1  # 这里的dataSet 最后一列是分类 numFeatures=2;我们按2列数据进行划分
    baseEntropy = calcShannonEnt(dataSet)  # 原始的熵 ,计算出整个数据数据集的熵
    bestInfoGain = 0
    bestFeature = -1
    for i in range(numFeatures):  # 循环每一列特征
        featList = [example[i] for example in dataSet]  # 创建一个新的 列表,存放数据集第 i 列的数据
        uniqueVales = set(featList)  # 使用集合,把数据去重
        newEntropy = 0  # 以下是计算每一列的熵 求某列最大的熵
        for value in uniqueVales:  # 循环第 i 列的特征值
            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 majorityCnt(classList):
    # 按分类后类别数量排序,比如:最后分类为2男1女,则判定为男;
    classCount = {
     }
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]


def createTree(dataSet, labels):
    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]  # bestFeatLabel = 列 描述
    myTree = {
     bestFeatLabel: {
     }}  # 分类结果以字典形式保存
    del (labels[bestFeat])  # 删除已计算过的列
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVales = set(featValues)  # 获取某列 所有不重复值
    for value in uniqueVales:
        subLabels = labels[:]
        myTree[bestFeatLabel][value] = createTree(splitDataSet \
                                                (dataSet, bestFeat, value), subLabels)  # 递归
    return myTree


if __name__ == '__main__':
    dataSet, labels = createDataSet1()  # 创造示列数据
    print(createTree(dataSet, labels))  # 输出决策树模型





结果
{
     '声音': {
     '细': '女', '粗': {
     '头发': {
     '短': '男', '长': '女'}}}}

你可能感兴趣的:(大数据,机器学习)