机器学习之决策树

  • 须知概念

  • 信息熵(information entropy):是度量样本集合纯度常用的一种指标。假定当前样本集合D中第k类样本所占等等比例为Pk(k = 1,2,…,|y|),则D的信息熵定义为
    在这里插入图片描述
    Ent(D)的值越低,则D的纯度越高

  • 信息增益(information gain):假定离散属性a有V个可能的取值{a1,a2,…,av},若使用a来对样本采集D来进行划分,则会产生V个分支节点,其中第v个分支节点包含了D中所有在属性a上取值为av 的样本,记为Dv .根据下面公式计算出Dv 的信息熵,由于不同分支结点包含的样本数不一样,给分支结点赋予权重|Dv|/|D|,即样本数越多的分支结点的影响越大,于是可知属性a对样本集进行划分所获得的‘信息增益’为
    在这里插入图片描述
    一般而言,信息增益越大,意为着使用属性a划分所获得的‘纯度提升越大’。

  • 决策树概述

1、决策树算法是一种基本的分类与回归的方法,是最经常使用的数据挖掘算法之一。
2、决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-then 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。
3、决策树学习通常包括3个步骤:特征选择、决策树生成和决策树的修剪。

  • 决策树的构造
通过递归函数createBranch()构造决策树
检测数据集中每个子项是否属于同一分类:
If so return 类标签;
Else 
    寻找划分数据集的最好特征
    划分数据集
    创建分支节点
    for 每个分支节点的子集
        调用函数createBranch并增加返回结果到分支节点中
    return 分支节点
  • 决策树的一般流程

(1)收集数据:可以使用任何方法。
(2)准备数据:树构造算法只适合用于标称型数据(目标变量的结果只在有限目标集中取值),因此数值型必须离散化。
(3)分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。
(4)训练数据:构造树的数据结构。
(5)测试算法:使用经验树计算错误率。
(6)使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据 的内在含义。

  • 决策树算法特点

优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据
缺点:可能会产生过度匹配问题
适用数据类型:数值型和标称型

  • 决策树项目案例
    判断鱼类与非鱼类
    海洋生物数据
import operator
from math import log

# 利用createDataSet()创建表格中的数据
def creatDataSet():
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']
    return dataSet, labels

# 计算给定数据集的香农熵
def calcShnnonEnt(dataSet):
    numEntries = len(dataSet)
    labelCount = {}
    '''
    dict = {key, value}
    '''
    for featVec in dataSet:
        currentLabel = featVec[-1]  # 将每个元素最后一个元素选择出来
        if currentLabel not in labelCount.keys():
            labelCount[currentLabel] = 0
        labelCount[currentLabel] += 1  # 对字典里的value加1   
    shnnonEnt = 0.0
    for key in labelCount:
        prob = float(labelCount[key]) / numEntries  # 计算类别各占的概率
        shnnonEnt -= prob * log(prob, 2)  # 计算熵
    return shnnonEnt

# 按照给定的特征划分数据集
def spiltDataSet(dataSet, axis, value):
    '''
    dataSet:待划分的数据集
    axis:划分数据集的特征
    value:特征的返回值
    '''

    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]  # 相当于创建一个新的列表list
            reducedFeatVec.extend(featVec[axis+1:])  # 输出每个元素除第一位的元素
            retDataSet.append(reducedFeatVec)
    return retDataSet

# 选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0])-1  # 特征的个数,去掉最后一个标签
    baseEntropy = calcShnnonEnt(dataSet)  # 整个数据集原始的熵
    bestInfoGain = 0.0
    bestFeature = -1  # 最优特征索引
    for i in range(numFeatures):   # 遍历所有特征
        featList = [example[i] for example in dataSet]  # 获取dataSet第i个特征:  第一个特征[1,1,1,0,0]或第二个特征[1,1,0,1,1]
        uniqueVals = set(featList)   # 将第i个特征的属性值放在一个集合里{0, 1}
        newEntropy = 0.0
        for value in uniqueVals:  # 遍历该特征所有的值{0,1}
            subDataSet = spiltDataSet(dataSet, i, value)  # i = 0/1, value = 0/1  如i=0,value=0,subDataSet= [[1,'no'], [1,'no']]没有有用的信息,熵的值为0
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShnnonEnt(subDataSet)
        infoGain = baseEntropy - newEntropy    # 信息增益,越大,表示按该属性划分所获得的‘纯度提升’越大
        if infoGain > bestInfoGain:
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

# 返回出现次数最多的分类名称
def majorityCnt(classList):
    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):   # count()函数是返回string 中某字符的次数
        return classList[0]
    '''
    递归第一个停止条件:所有的类标签完全相同,直接返回该类标签
    '''
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    print(bestFeat)
    bestFeatlabel = labels[bestFeat]
    mytree = {bestFeatlabel : {}}
    del(labels[bestFeat])   # del表示删除
    # 将已选维度标签从标签列表中删除
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)  # {0,1}
    for value in uniqueVals:
        sublabels = labels[:]
        mytree[bestFeatlabel][value] = createTree(spiltDataSet(dataSet, bestFeat, value),
                                                               sublabels)     # 递归,自己调用自己createTree()
    return mytree
输出结果
myDat =  [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
myTree =  {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
  • 测试算法:使用决策树执行分类
def classify(inputTree, featLabels, testvec):
    '''
    inputTree: 决策树模型
    featLabels: Feature标签对应的名称
    testvec: 测试输入的数据
    return: classLabels 分类结果
    '''
    firstStr = list(inputTree.keys())[0]  # 获取tree根节点对应的key值
    secondDict = inputTree[firstStr]      # 通过key得到根节点对应的value
    # 判断根节点名称获取根节点在label中的先后顺序,这样就知道输入的testVec怎么开始对照树来做分类
    featIndex = featLabels.index(firstStr)
    for key in secondDict.keys():
        if testvec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabels = classify(secondDict[key], featLabels, testvec)
            else:
                classLabels = secondDict[key]
    return classLabels

在测试中,会报这样的错 ValueError: ‘no surfacing’ is not in list 是由于之前createTree()中将已选的标签从列表中删除了,所以只需重新添加 labels 就行了

  • 决策树存储
# 使用pickle模块存储决策树
def storeTree(inputTree, filename):
    import pickle
    # fw = open(filename, 'w')
    fw = open(filename, 'wb')
    pickle.dump(inputTree, fw)
    fw.close()

def grabTree(filename):
    import pickle
    # fr = open(filename)
    fr = open(filename, 'rb')
    return pickle.load(fr)

需要注意Python3写法不一致:
1、fw = open(filename, ‘w’) 会报错:TypeError: write() argument must be str, not bytes,所以要写成fw = open(filename, ‘wb’)
2、fr = open(filename) 也会报错:UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0x80 in position 0: illegal multibyte sequence,所以因写成 fr = open(filename, ‘rb’)

  • 该项目最大信息增益计算

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树是常用的机器学习算法之一,通过对数据的分类和特征值计算来完成对未知数据的预测。本文将介绍使用Python实现决策树算法的相关步骤。 首先,需要导入决策树算法工具包,使用以下代码: ```python from sklearn import tree ``` 然后,导入训练数据和测试数据,并进行预处理。为了方便起见,在本文中采用生成随机数的方式来生成样本数据,使用以下代码: ```python from sklearn.datasets import make_classification X, y = make_classification(n_samples=100, n_features=4, n_classes=2, n_informative=2, n_redundant=0, random_state=0, shuffle=False) ``` 接下来,使用生成的样本数据进行模型训练。这里使用scikit-learn中的DecisionTreeClassifier()函数。 ```python clf = tree.DecisionTreeClassifier() clf = clf.fit(X, y) ``` 训练后,调用predict()方法进行对测试数据的预测,使用以下代码: ```python y_pred = clf.predict(X) ``` 最后,评估模型的准确率,使用以下代码: ```python from sklearn.metrics import accuracy_score print(accuracy_score(y, y_pred)) ``` 这就是使用Python实现决策树算法的基本过程。决策树可以根据数据中的不同特征进行分类,是一个简单且常用的分类算法。决策树算法也可用于回归问题,例如预测一个数的大小。与其他机器学习算法相比,决策树具有易于理解和可解释的优点,同时还可以处理非线性的分类问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值