0
点赞
收藏
分享

微信扫一扫

基于决策树实现葡萄酒分类——sklearn接口调用实现

决策树算法总结

算法思想

给定一个样本集合D,其中每个样本由若干个属性表示,决策树通过贪心策略(如 ID3 / C4.5 / CART)不断挑选最优的属性,将每个样本划分到不同的子树,再在各棵子树上通过递归对子树上的样本进行划分,直到满足一定的终止条件为止。

决策树的每个叶节点对应一个分类,非叶节点对应某个属性上的划分,根据样本在该属性上的不同取值将其划分为若干子集。


算法基本框架(伪代码)

输入:训练集D = {(X1,Y1),(X2,Y2), ..., (Xn,Yn)}
     属性集A = {A1, A2, ..., Am}  (即Xi含m个特征属性,i=1,2,...,n) 
输出:构建好的决策树

def BuildDecisionTree(D, A){  
    node = New Node();    // 新键一个节点
    if (D为空集){
        return node;
    }
    else if(Y1 == Y2 == ... ==Yn ==C){     // D中的所有样本都属于同一类别 C  
        node为叶节点,其标记为C;
        return node;
    }
    else if( "A为空" or "D中的样本在A上的取值都相同"){    // A为空表示:已没有可以用于继续划分的属性
        node 为叶节点, 标记为 D 中最频繁的类别;
        return node;
    }
    else{
        从 A 中选择最优划分属性 A* (使用信息增益或其他准则,应用贪心算法策略有不同的效果,也是构建决策树的关键步骤)  

        对于 A* 的每一个值v{  
            为 D 中 A* = v 的样本创建一个分支节点  
            Dv = {(Xj,Yj) | Xj_A* = v, j=1,2,...,n}    //令 Dv 为 D 中 A* = v 的样本集合(Dv为D的子集 ,Xj_A*为第j个样本的属性A*的属性值
            if Dv 为空:  
                添加一个叶节点到分支节点,标记为 D 中最频繁的类别  
            else:  
                添加 BuildDecisionTree(Dv, A - {A*}) 到分支节点  
        }
    }
    返回 生成的树  
}

策略对比

采用不同的贪心策略(属性选择度量标准不同)生成最终的决策树会引起BuildDecisionTree的不同;另外在实际应用中,可能还需要考虑处理缺失值、剪枝(避免过拟合)等问题。

ID3:采用信息增益

# 计算属性a的信息增益(信息增益表示划分前后数据集纯度的提升程度,信息增益越大,表示使用属性 a 划分数据集的效果越好。)
def CalculateInformationGain(D, A, a): 
    计算 D 的熵 H(D) = CalculateEntropy(D)
    对于 a 的每一个值 v:  
        计算 Dv 的大小 |Dv|  
        计算条件熵 H(D|a)  # 给定某个属性 a 后,数据集 D 的条件熵表示了按 a 划分后数据集的纯度。
    信息增益 Gain(D, a) = H(D) - H(D|a)  
    return Gain(D, a)  

# 计算样本集 D 的熵(Entropy,是衡量数据集纯度的一个指标,熵越小,数据集的纯度越高)
def CalculateEntropy(D):  
    对于 D 中的每个类别 C:  
        计算 C 的概率 p(C)  
    H(D) = -Σ p(C) * log2(p(C))  
    return H(D)

优点

方法简单,学习能力强

缺点

选择具有大量值的属性的倾向;没有考虑连续特征;属性相互关系强调不够,容易导致子树重复或某些属性被重复检验;容易过拟合


C4.5:采用增益率

C4.5是ID3算法的改进版本,采用增益率(Gain Ratio)作为分支指标,旨在克服信息增益偏向于选择取值数目较多的属性的问题。增益率通过引入一个分裂信息(Split Information)的项来惩罚取值数目多的属性

def CalculateGainRatio(D, A, a):  
    信息增益 Gain(D, a) = CalculateInformationGain(D, A, a)
    # 计算 a 的分裂信息 SplitInfo(D, a),用来衡量根据属性a将数据集D划分成多个子集时的不确定性
    对于 a 的每一个唯一值 v:  
        计算 Dv 的大小 |Dv|  
        计算该分支的概率 p(v) = |Dv| / |D|  
        SplitInfo(D, a) = -Σ p(v) * log2(p(v))
    if SplitInfo(D, a) == 0:  
        return 0  # 避免除以零
    计算增益率 GainRatio(D, a) = Gain(D, a) / SplitInfo(D, a)
    return GainRatio(D, a)

优点:尽量克服了ID3算法的缺点;能处理非离散数据或不完整数据

缺点:大量的运算耗费资源,且只能用于分类


CART:采用基尼指数

CART全称为Classification and Regression Tree,分类回归树,是如今主要使用的用于实现决策树的算法。

基尼指数用来衡量数据的不纯度或不确定性。

基于决策树实现葡萄酒分类——sklearn接口调用实现_熵

决策树中的基尼指数计算:

基于决策树实现葡萄酒分类——sklearn接口调用实现_ID3_02

注:一般情况下,CART算法实现的决策树是一棵二叉树,而前两种算法生成的决策树一般是多叉树


实验-决策树模型实现葡萄酒分类

相关库的导入与说明

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
import numpy as np
import os

np.random.seed(0)  # 为了保证每次随机实验的结果一致

sklearn.tree.DecisionTreeClassifier

DecisionTreeClassifier是 scikit-learn 库中用于分类任务的决策树模型,实现了决策树的构建、分类预测、决策树评价。该模型通过递归地将特征空间划分为若干个简单的区域来做出预测,每个区域都输出一个简单的预测值(通常是该区域内训练样本中最常见的类别)。

核心参数(构造函数参数):
    criterion : {"gini", "entropy", "log_loss"}, default="gini"
        规定了该决策树所采用的最佳分割属性的判决方法(采用的度量标准)
        "gini", "entropy", "log_loss" 分别对应 CART、ID3、C4.5算法
    max_depth : int, default=None
        限制决策树的最大深度,默认不限制;进行限制有助于防止过拟合
    min_samples_leaf : int or float, default=1
        限定了叶节点包含的最小样本数
        - If float, then `min_samples_leaf` is a fraction and
          `ceil(min_samples_leaf * n_samples)` are the minimum
          number of samples for each node
常用实例方法:
	fit(XTrain,YTrain):
    	根据给定的样本特征数据和对应的标签数据构建决策树
    score(XTest,YTest):
    	使用构建好的决策树对若干样本特征XTest进行标签预测,并与真实标签YTest对比最后返回准确率。
    predict(XTest):
    	使用构建好的决策树对若干样本特征XTest进行标签预测并返回预测的标签数据

sklearn.tree的export_graphviz()方法

常用调用形式:

# model为成功执行fit()方法后的决策树对象
export_graphviz(model, out_file='xxxxxxTree.dot')

该函数将决策树模型以 DOT 格式导出,通过生成的 DOT 文件,用户可以使用 Graphviz 的工具(如 dot 命令行工具,需要自行另外安装在系统中)将决策树转换为PNG图片或PDF文件,这样可直观地看到决策树的结构,可视化决策树的决策过程。


加载葡萄酒数据

# 获取训练集、测试集
wines = load_wine()
X, Y = wines.data, wines.target
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2)

通过PyCharm的调试功能可以看看sklearn内置的葡萄酒数据的相关信息。共有178个样本,每个样本13个特征,样本标签共3类。

基于决策树实现葡萄酒分类——sklearn接口调用实现_C4.5_03


决策树三种构建策略的对比实验

def decisionTreeExperiment(criterion = "gini"):
    # 获取决策树模型
    model = DecisionTreeClassifier(criterion=criterion)
    model.fit(X_train, y_train)

    # 可视化生成的决策树
    dot_file = f"DecisionTreeWithCriterion={criterion}.dot"
    export_graphviz(model, out_file=dot_file)

    p = os.path.join(os.getcwd(),dot_file)
    commandText = f"dot -Tpng {p} -o {dot_file[:-4]}.png"  # 注意,需要去 Graphviz 的官方网站下载适用于你操作系统的安装程序
    print('命令终端执行如下命令可获取可视化的决策树效果:\n',commandText)

    # 模型评估
    trainScore = model.score(X_train, y_train)
    testScore = model.score(X_test, y_test)
    print("DecisionTree experiment with 'criterion={}' ".format(criterion))
    print(f'\t trainScore:{trainScore} \n\t testScore:{testScore}\n')

基于决策树实现葡萄酒分类——sklearn接口调用实现_ID3_04

对比实验,三种决策树算法的应用:

dict_algorithm2criterion = {'ID3':'entropy', 'C4.5':'log_loss', "CART":'gini'}
for k, criterion in dict_algorithm2criterion.items():
    print(k)
    decisionTreeExperiment(criterion)

运行结果:

基于决策树实现葡萄酒分类——sklearn接口调用实现_C4.5_05

初步来看,ID3、C4.5、CART三种策略的效果依次增强。


决策树可视化

在安装了的系统的命令终端上执行dot命令将代码生成的三个dot文件转为png图片(将-Tpng替换为-Tpdf即将dot文件转为pdf文件):

dot -Tpng xxxxxxTree.dot -o  xxxxxxTree.png

基于决策树实现葡萄酒分类——sklearn接口调用实现_决策树_06

基于决策树实现葡萄酒分类——sklearn接口调用实现_熵_07

生成的三棵决策树中,除了使用gini标准生成的决策树外,其它两棵决策树的总节点数为样本的特征树目(13个)。

基于决策树实现葡萄酒分类——sklearn接口调用实现_C4.5_08

图中每个非叶子节点(下同)包含四个数据:决策条件(样本的某个特征的特征值,或者某个属性的属性值与特定数值的比较)、度量标准及其值、样本数、每个类别的个数。叶子节点没有“决策条件”这个数据是因为叶子节点不用再根据条件再进行分裂了。

基于决策树实现葡萄酒分类——sklearn接口调用实现_CART_09


基于决策树实现葡萄酒分类——sklearn接口调用实现_决策树_10

  1. 注:叶节点所包含的样本都属于同一类别,如value = [0, 0, 42]表示该叶节点只有42个标签为第三类的样本。这决定了决策树预测新样本的过程。

决策树预测新样本

构建好后的决策树对新样本进行预测的过程相对直观且系统化,一般过程:

  1. 从根节点开始
  1. 将新样本的特征值输入到决策树的根节点。
  1. 特征值测试(决策条件判断)
  1. 在当前节点上,根据该节点的特征属性对新样本进行相应的测试。
  2. 测试结果将决定下一步应该走向哪个子节点。
  1. 递归遍历
  1. 根据测试结果,移动到相应的子节点上。
  2. 在新的子节点上重复进行特征值测试,直到达到一个叶节点。
  1. 输出预测结果
  1. 当达到叶节点时,该叶节点所代表的类别或数值即为对新样本的预测结果。

基于决策树实现葡萄酒分类——sklearn接口调用实现_CART_11

上一篇:k-近邻算法实现鸢尾花分类-sklearn接口调用

举报

相关推荐

0 条评论