机器学习 -决策树算法中子数据集的划分

简介: 本文介绍机器学习 -决策树算法中,子数据集的划分及其Python实现

决策树算法中子数据集的划分


Note: 本文中的代码另外有采用了TypeScript/JavaScript进行实现的版本。作者关注到,谷歌TensorFlow团队近几年在JavaScript语言上动作频频,自推出同接口的JavaSccript版本TensorFlow.js后,在2020年先后右推出与Pandas同接口的JavaScript版本库"Danfo.js",同时配套推出了一个类似于Jupyter的笔记本"Dnotebook"(Danfo Dotebook,这个笔记本不好用,但动向很引发人们的关注)。紧接着改团队出版了JavaScript领域头一本以TensorFlow为主详细讲解深度学习的图书,并在不久后于2021年4月被翻译为中文版在人民邮电出版社发行,他就是斯坦利`比列斯奇等人所著的《JavaScript深度学习》。本文笔者认为,使用JavaScript家族的语言实现数据领域的相关算法在未来有助于实现分布式的云计算等潜在商业价值巨大的特点,同时相比于Python语言,JavaScript(含TypeScript等)更能绘制精致并且具有动态效果的图标,数据可视化能力更是远非Python可比。对于感兴趣的同学可以参考本文的TypeScript/JavaScript版本,链接:TypeScript机器学习:决策树算法中子数据集的划分

李俊才 的 CSDN 博客

已入驻阿里云博客

邮箱 :291148484@163.com
本文地址
- https://developer.aliyun.com/article/
- https://blog.csdn.net/qq_28550263/article/details/123649691

阅读本文后推荐先阅读:信息增益与信息增益率计算的Python实现https://blog.csdn.net/qq_28550263/article/details/114891368


目 录


1. 经典决策树算法思想回顾

2.为什么需要划分数据集

3. 如何进行数据集的划分

附: 举个更简单的实例


导读: 本文我们将解决两个问题,一个是为什么我们要划分数据集,另一个是如何用代码实现数据集划分。

1. 经典决策树算法思想回顾

决策树算法包括建树(训练)和查树(决策/预测)两个环节。在决策树算法的训练过程中对于决定一个事件最终决策的多个特征(决策考虑因素),我们一般基于如信息增益率、基尼系数等指标先确定出一个能最大化获取信息的特征作为当前最佳特征。一个特征映射为在一颗决策树中的一个节点。

第一个“最佳特征”对应的·节点我们称之为根节点。每次到达一个节点处,我们依据节点处特征的不同取值,对节点进行分支以生长出其子节点,子节点处继续着它们各自父辈的故事。直到某个时候,不满足人为干预的一些条件了,或者完美地完成分类了,这时子节点不再继续分支而成为决策树的叶子节点

2.为什么需要划分数据集

已经说过,在决策树训练过程中需要不断地进行分支操作。从一颗树的生长过程来看每次分支是为了去树的下一个节点,而对应成特征的角度说,分支的本质其实是使用了上一个一个特征仍然没能完成最终决策时,使用下一个特征进行继续决策

在我们的标签集(labels)中,它在训练之初拥有多条数据,每条数据都对应了实际情况中每个特征的取值。一次分支使用到的时一个特征,实际上就是比对哪些数据条需要划分到该该特征分支值与这条数据在该特征下取值相等的一侧。

从上面我们看到,只有划分数据集才能让数据集中的每一条数据各有归属,这就是为什么我们需要划分数据集。

举一个小例子并用绘图来示意。

【引例】:李华是否打球的决策分析。

以下是李华在过去9天是否打球的历史数据(原始数据集):

6666666666666.png

假设我们现在确定了"有课与否"作为是否打球的判断依据进行第一次划分,那么有两种分支情况:

6666666666666.png

3. 如何进行数据集的划分(Python代码的实现)

3.1 划分步骤的详解

依上所述,划分数据集以获取子数据集的过程就是一个数据过滤的过程。这个过程的实现需要我们做两件事:

  • 一是过滤掉非节点特征当前之路取值的数据
  • 而是要在当前特征值划分所有数据过滤完成之后,删除已经用过的特征。

在上例中,以验证"有课与否"取"Y"划分数据集为例:

  • 第一步:过滤掉所有"有课与否"取"N"的数据,得到结果如下:6666666666666.png
  • 第二步:删除已经用过的特征"有课与否",得到本次划分最终完成的数据集如下:6666666666666.png

3.2 使用编程实现对数据集的划分

在理解了上述过程之后,我们趁热打铁,使用Python语言来编程实现该数据集划分的全部过程。

假设用x_trainy_train来表示训练集数据的特征列取值们与标签列,它们分别是多维和一维数组。

为了方便读者观察,以拥有10条数据、一共43个特征的数据集为例,其中x_train的样式形如:

array([[1, 4, 2, 0, 3, 1, 1, 0, 1, 4, 2, 4, 4, 2, 4, 2, 0, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 1, 3, 1, 3, 1, 1, 0, 1, 4, 3, 4, 4, 2],
       [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 3, 0, 3, 1, 1, 0, 0, 4, 2, 2, 4, 1, 1, 0, -1, 0, 4, 0, -1, -1, 0, 0, 0, 0, 0, 0, 2],
       [4, 2, 2, 3, 1, 2, 1, 1, 0, 2, 1, 1, 1, 0, 3, 0, 3, 2, 2, 0, 0, 0, 0, 3, 1, 1, 2, 3, 4, 3, 1, 1, 3, 1, 2, 1, 1, 0, 1, 2, 2, 1, 0],
       [1, 4, 2, 2, 3, 1, 1, 0, 0, 2, 1, 1, 1, 0, 3, 4, 2, 2, 4, 1, 0, 1, 0, 3, 2, 2, 4, 3, 1, 2, -1, 2, 2, 1, 0, 1, -1, 0, 1, 1, 1, 0, 0],
       [1, 2, 2, 1, 3, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 4, 1, 2, 1, 0, 0, 0, 0, 2, 1, 1, 2, 3, 3, 0, -1, 2, 1, 3, 1, 1, 0, 0, 2, 3, 2, 1, 0],
       [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 3, 3, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 2, 4, 2, 2, -1, 2, 2, 3, 0, 0, 0, 0, 2, 2, 2, 2, 0],
       [1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 3, 2, 1, 1, 0, 2, 2, 1, 0, 3, 3, 2, 1, 1, 3, 0, -2, -1, -1, 0, 1, 0, 2, 2, 1],
       [0, 0, 3, 3, 2, 0, 0, 0, 0, 3, 3, 3, 0, 2, 1, 3, 3, 3, 2, 1, 1, 0, 0, 3, 4, 4, 1, 2, 1, 0, 1, 2, 2, 1, -1, -1, 0, 0, 2, 1, 2, 1, 2],
       [2, 4, 2, 0, 2, 1, 0, 1, 0, 2, 2, 3, 4, 2, 2, 3, 0, 2, 0, 1, 1, 0, 0, 0, 3, 3, 0, 4, 2, 2, 1, 3, 1, 4, 0, -1, 1, 0, 3, 1, 2, 4, 0],
       [1, 4, 1, 0, 1, 0, 0, 0, 0, 3, 2, 3, 3, 4, 4, 1, 0, 1, 0, 1, 0, 1, 0, 0, 2, 1, 4, 2, 0, 4, 1, 3, 1, 3, -1, 0, -1, 0, 3, 2, 3, 2, 3]],
      dtype=object)

其中y_train的样式形如:

array([1, 0, 0, 1, 0, 0, 1, 0, 0, 1], dtype=int64)

接下来到了激动人心的数据集划分函数dividing_data_set()的编程环节。

为了方便在数据集中索引到各个特征,我们先将数据集转换为方便索引的数据字典。以下采用jupyter调试。

importnumpyasnp# 定义模拟数据x_train= ... # 采用上面的x_train,这里省略y_train= ... # 采用上面的y_train,这里省略features= ["feature_"+str(i) foriinrange(43)]  # 产生43个不同的特征名字node_feature="feature_13"# 定义当前节点的特征名node_feature_value=2# 定义对于当前节点的特征取值为2,之后就是求 node_feature 在 node_feature取2下的划分# 转换为数据集字典date_set=dict(zip(features,x_train.T))   # 注意x_train需要转置date_set.update({"labels":y_train})        # 将标签集(labels,也就是输出y们)也加入数据集
date_set   # 查看一下整理的数据样式

Out[i]:

{'feature_0': array([1, 0, 4, 1, 1, 1, 1, 0, 2, 1]),
 'feature_1': array([4, 0, 2, 4, 2, 0, 1, 0, 4, 4]),
 'feature_2': array([2, 0, 2, 2, 2, 0, 0, 3, 2, 1]),
 'feature_3': array([0, 3, 3, 2, 1, 0, 2, 3, 0, 0]),
 'feature_4': array([3, 0, 1, 3, 3, 1, 0, 2, 2, 1]),
 'feature_5': array([1, 0, 2, 1, 1, 0, 0, 0, 1, 0]),
 'feature_6': array([1, 0, 1, 1, 1, 0, 0, 0, 0, 0]),
 'feature_7': array([0, 0, 1, 0, 0, 0, 0, 0, 1, 0]),
 'feature_8': array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
 'feature_9': array([4, 0, 2, 2, 2, 1, 0, 3, 2, 3]),
 'feature_10': array([2, 0, 1, 1, 2, 3, 0, 3, 2, 2]),
 'feature_11': array([4, 0, 1, 1, 1, 3, 0, 3, 3, 3]),
 'feature_12': array([4, 1, 1, 1, 1, 2, 0, 0, 4, 3]),
 'feature_13': array([2, 2, 0, 0, 0, 0, 2, 2, 2, 4]),
 'feature_14': array([4, 1, 3, 3, 0, 1, 0, 1, 2, 4]),
 'feature_15': array([2, 2, 0, 4, 4, 0, 0, 3, 3, 1]),
 'feature_16': array([0, 3, 3, 2, 1, 0, 2, 3, 0, 0]),
 'feature_17': array([2, 0, 2, 2, 2, 0, 0, 3, 2, 1]),
 'feature_18': array([2, 3, 2, 4, 1, 0, 3, 2, 0, 0]),
 'feature_19': array([0, 1, 0, 1, 0, 0, 2, 1, 1, 1]),
 'feature_20': array([0, 1, 0, 0, 0, 0, 1, 1, 1, 0]),
 'feature_21': array([0, 0, 0, 1, 0, 0, 1, 0, 0, 1]),
 'feature_22': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
 'feature_23': array([0, 4, 3, 3, 2, 1, 2, 3, 0, 0]),
 'feature_24': array([1, 2, 1, 2, 1, 3, 2, 4, 3, 2]),
 'feature_25': array([0, 2, 1, 2, 1, 3, 1, 4, 3, 1]),
 'feature_26': array([0, 4, 2, 4, 2, 2, 0, 1, 0, 4]),
 'feature_27': array([2, 1, 3, 3, 3, 4, 3, 2, 4, 2]),
 'feature_28': array([0, 1, 4, 1, 3, 2, 3, 1, 2, 0]),
 'feature_29': array([3, 0, 3, 2, 0, 2, 2, 0, 2, 4]),
 'feature_30': array([ 1, -1,  1, -1, -1, -1,  1,  1,  1,  1]),
 'feature_31': array([3, 0, 1, 2, 2, 2, 1, 2, 3, 3]),
 'feature_32': array([1, 4, 3, 2, 1, 2, 3, 2, 1, 1]),
 'feature_33': array([3, 0, 1, 1, 3, 3, 0, 1, 4, 3]),
 'feature_34': array([ 1, -1,  2,  0,  1,  0, -2, -1,  0, -1]),
 'feature_35': array([ 1, -1,  1,  1,  1,  0, -1, -1, -1,  0]),
 'feature_36': array([ 0,  0,  1, -1,  0,  0, -1,  0,  1, -1]),
 'feature_37': array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
 'feature_38': array([4, 0, 1, 1, 2, 2, 1, 2, 3, 3]),
 'feature_39': array([3, 0, 2, 1, 3, 2, 0, 1, 1, 2]),
 'feature_40': array([4, 0, 2, 1, 2, 2, 2, 2, 2, 3]),
 'feature_41': array([4, 0, 1, 0, 1, 2, 2, 1, 4, 2]),
 'feature_42': array([2, 2, 0, 0, 0, 0, 1, 2, 0, 3]),
 'labels': array([1, 0, 0, 1, 0, 0, 1, 0, 0, 1])}
defdividing_data_set(date_set,node_feature,node_feature_value):
"""    划分数据集    整个划分方法的思想是"记录索引-重索引"。简而言之就是先记住特征取值为指定取值的索引号,然    后依据记录索引号保对其它特征下同索引号的元素进行保留。最终实现留下当前划分数据条的目的。    Parameters    ----------    date_set: "dict"结构的数据集,其中键为”labels“的键值对对应为标签集(源于x_train),其余               的对应为特征取值键值对(源于y_train)。    node_feature:可以是num、str等类型,但是必须和date_set中的键的类型保持一致。表示需要划分               数据集的节点处对应的特征名。    node_feature_value:是对应与 node_feature 的一个特定取值。    Returns    -------    result : dict        返回子数据集字典,其形式与date_set保持一致。其中键`labels`对应的值类似是子标签集数组。    """# 先获取对应特征 node_feature 在数据集中所有条数据的有序取值数组feature_in_sets=date_set[node_feature]
# 记录所有取值为 node_feature_value 数据编号reserved_group= [iforiinrange(len(feature_in_sets)) iffeature_in_sets[i]==node_feature_value]
# 接着依据 reserved_group 中的组号保留属于当前分支的数据sub_date_set= {}
forthe_keyindate_set:
sub_date_set[the_key] =np.array([date_set[the_key][i] foriinreserved_group])
# 最后,删除用过的特征列del(sub_date_set[node_feature])
returnsub_date_set# 调用函数,执行子数据集划分dividing_data_set(date_set,node_feature,node_feature_value)

Out[i]:

{'feature_0': array([1, 0, 1, 0, 2]),
 'feature_1': array([4, 0, 1, 0, 4]),
 'feature_2': array([2, 0, 0, 3, 2]),
 'feature_3': array([0, 3, 2, 3, 0]),
 'feature_4': array([3, 0, 0, 2, 2]),
 'feature_5': array([1, 0, 0, 0, 1]),
 'feature_6': array([1, 0, 0, 0, 0]),
 'feature_7': array([0, 0, 0, 0, 1]),
 'feature_8': array([1, 0, 0, 0, 0]),
 'feature_9': array([4, 0, 0, 3, 2]),
 'feature_10': array([2, 0, 0, 3, 2]),
 'feature_11': array([4, 0, 0, 3, 3]),
 'feature_12': array([4, 1, 0, 0, 4]),
 'feature_14': array([4, 1, 0, 1, 2]),
 'feature_15': array([2, 2, 0, 3, 3]),
 'feature_16': array([0, 3, 2, 3, 0]),
 'feature_17': array([2, 0, 0, 3, 2]),
 'feature_18': array([2, 3, 3, 2, 0]),
 'feature_19': array([0, 1, 2, 1, 1]),
 'feature_20': array([0, 1, 1, 1, 1]),
 'feature_21': array([0, 0, 1, 0, 0]),
 'feature_22': array([0, 0, 0, 0, 0]),
 'feature_23': array([0, 4, 2, 3, 0]),
 'feature_24': array([1, 2, 2, 4, 3]),
 'feature_25': array([0, 2, 1, 4, 3]),
 'feature_26': array([0, 4, 0, 1, 0]),
 'feature_27': array([2, 1, 3, 2, 4]),
 'feature_28': array([0, 1, 3, 1, 2]),
 'feature_29': array([3, 0, 2, 0, 2]),
 'feature_30': array([ 1, -1,  1,  1,  1]),
 'feature_31': array([3, 0, 1, 2, 3]),
 'feature_32': array([1, 4, 3, 2, 1]),
 'feature_33': array([3, 0, 0, 1, 4]),
 'feature_34': array([ 1, -1, -2, -1,  0]),
 'feature_35': array([ 1, -1, -1, -1, -1]),
 'feature_36': array([ 0,  0, -1,  0,  1]),
 'feature_37': array([1, 0, 0, 0, 0]),
 'feature_38': array([4, 0, 1, 2, 3]),
 'feature_39': array([3, 0, 0, 1, 1]),
 'feature_40': array([4, 0, 2, 2, 2]),
 'feature_41': array([4, 0, 2, 1, 4]),
 'feature_42': array([2, 2, 1, 2, 0]),
 'labels': array([1, 0, 1, 0, 0])}

可以看到,划分数据集后在子数据集中,所有特征中对应划分前"feature_13"取值为2的数据被保留了下来,同时由于特征"feature_13"已经使用过了,子数据集中不再有"feature_13"。符合数据集划分要求。


附: 举个更简单的实例

Q:上面例子数据太复杂了,我没看明白。能否用文章开头的引例给我们来一次?
A:必须安排!
importnumpyasnp# 定义数据x_train=np.array([["Y","晴天","好"],
                    ["Y","雨天","差"],
                    ["N","太阳","好"],
                    ["N","雨天","差"],
                    ["N","晴天","差"],
                    ["Y","雨天","一般"],
                    ["N","雨天","好"],
                    ["N","晴天","好"],
                    ["Y","晴天","好"],
                   ])
y_train=np.array(["N", "N", "Y", "Y", "Y", "N", "Y", "Y", "Y"])
features= ["有课与否","天气","心情"]      # 产生43个不同的特征名字node_feature="有课与否"# 定义当前节点的特征名node_feature_value="Y"# 定义对于当前节点的特征取值为2,之后就是求 node_feature 在 node_feature取2下的划分# 转换为数据集字典date_set=dict(zip(features,x_train.T)) # 注意需要转置date_set.update({"labels":y_train})      # 将标签集(labels,也就是输出y们)也加入数据集
date_set

Out[i]:

{'有课与否': array(['Y', 'Y', 'N', 'N', 'N', 'Y', 'N', 'N', 'Y'], dtype='<U2'),
 '天气': array(['晴天', '雨天', '太阳', '雨天', '晴天', '雨天', '雨天', '晴天', '晴天'], dtype='<U2'),
 '心情': array(['好', '差', '好', '差', '差', '一般', '好', '好', '好'], dtype='<U2'),
 'labels': array(['N', 'N', 'Y', 'Y', 'Y', 'N', 'Y', 'Y', 'Y'], dtype='<U1')}
defdividing_data_set(date_set,node_feature,node_feature_value):
"""划分数据集"""# 先获取对应特征 node_feature 在数据集中所有条数据的有序取值数组feature_in_sets=date_set[node_feature]
# 记录所有取值为 node_feature_value 数据编号reserved_group= [iforiinrange(len(feature_in_sets)) iffeature_in_sets[i]==node_feature_value]
# 接着依据 reserved_group 中的组号保留属于当前分支的数据sub_date_set= {}
forthe_keyindate_set:
sub_date_set[the_key] =np.array([date_set[the_key][i] foriinreserved_group])
# 最后,删除用过的特征列del(sub_date_set[node_feature])
returnsub_date_setdividing_data_set(date_set,node_feature,node_feature_value)

Out[i]:

{'天气': array(['晴天', '雨天', '雨天', '晴天'], dtype='<U2'),
 '心情': array(['好', '差', '一般', '好'], dtype='<U2'),
 'labels': array(['N', 'N', 'N', 'Y'], dtype='<U1')}

这不就是在文章开头的引例中,我们手动划分当特征'有课与否'"Y"下的子数据集的么:

6666666666666.png

觉得写的不错或者对你有帮助的话,记得来个三连加关注噢!

目录
相关文章
|
12天前
|
机器学习/深度学习 算法 Python
探索机器学习中的决策树算法:从理论到实践
【10月更文挑战第5天】本文旨在通过浅显易懂的语言,带领读者了解并实现一个基础的决策树模型。我们将从决策树的基本概念出发,逐步深入其构建过程,包括特征选择、树的生成与剪枝等关键技术点,并以一个简单的例子演示如何用Python代码实现一个决策树分类器。文章不仅注重理论阐述,更侧重于实际操作,以期帮助初学者快速入门并在真实数据上应用这一算法。
|
1月前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【9月更文挑战第12天】决策树算法作为机器学习领域的一颗明珠,凭借其直观易懂和强大的解释能力,在分类与回归任务中表现出色。相比传统统计方法,决策树通过简单的分支逻辑实现了数据的精准分类。本文将借助Python和scikit-learn库,以鸢尾花数据集为例,展示如何使用决策树进行分类,并探讨其优势与局限。通过构建一系列条件判断,决策树不仅模拟了人类决策过程,还确保了结果的可追溯性和可解释性。无论您是新手还是专家,都能轻松上手,享受机器学习的乐趣。
43 9
|
18天前
|
机器学习/深度学习 人工智能 算法
【机器学习】决策树算法
【机器学习】决策树算法
|
2月前
|
机器学习/深度学习 算法 数据可视化
决策树算法介绍:原理与案例实现
决策树算法介绍:原理与案例实现
|
2月前
|
数据采集 机器学习/深度学习 算法
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
|
2月前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【8月更文挑战第2天】决策树算法以其直观性和解释性在机器学习领域中独具魅力,尤其擅长处理非线性关系。相较于复杂模型,决策树通过简单的分支逻辑实现数据分类,易于理解和应用。本示例通过Python的scikit-learn库演示了使用决策树对鸢尾花数据集进行分类的过程,并计算了预测准确性。虽然决策树优势明显,但也存在过拟合等问题。即便如此,无论是初学者还是专家都能借助决策树的力量提升数据分析能力。
40 4
|
2月前
|
机器学习/深度学习 数据可视化 算法
决策树VS世界:掌握Python机器学习中的这棵树,决策从此不再迷茫
【8月更文挑战第2天】在数据驱动时代,决策树作为一种直观且易于解释的机器学习方法,因其强大的分类与回归能力备受青睐。本文介绍决策树的基础概念:通过属性测试划分数据,优化选择以提高预测准确度。使用Python的scikit-learn库,我们演示了如何加载鸢尾花数据集,构建并训练决策树模型,评估其准确性,以及利用`plot_tree`函数可视化决策过程,从而更好地理解模型的工作原理。掌握这些技能,你将在面对复杂决策时更加自信。
24 2
|
3月前
|
存储 算法 Python
Python算法界的秘密武器:分治法巧解难题,贪心算法快速决策,动态规划优化未来!
【7月更文挑战第9天】Python中的分治、贪心和动态规划是三大关键算法。分治法将大问题分解为小问题求解,如归并排序;贪心算法每步选局部最优解,不保证全局最优,如找零钱;动态规划存储子问题解求全局最优,如斐波那契数列。选择合适算法能提升编程效率。
61 1
|
3月前
|
算法 Python
决策树算法详细介绍原理和实现
决策树算法详细介绍原理和实现
|
12天前
|
机器学习/深度学习 人工智能 自然语言处理
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024
阿里云人工智能平台 PAI 团队发表的图像编辑算法论文在 MM2024 上正式亮相发表。ACM MM(ACM国际多媒体会议)是国际多媒体领域的顶级会议,旨在为研究人员、工程师和行业专家提供一个交流平台,以展示在多媒体领域的最新研究成果、技术进展和应用案例。其主题涵盖了图像处理、视频分析、音频处理、社交媒体和多媒体系统等广泛领域。此次入选标志着阿里云人工智能平台 PAI 在图像编辑算法方面的研究获得了学术界的充分认可。
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024

热门文章

最新文章