决策树学习笔记

1、决策树的概念

顾名思义,决策树是用来:根据已知的若干条件,来对事件作出判断。从根节点到叶子节点,是将不同特征不断划分的过程,最后将类别分出。

在理论学习前,先了解下面一个例子:

如下图所示,根据“不浮出水面是否可以生存”和“是否有脚蹼”两种特征来判断该海洋动物是否鱼类。图中有5个样本,样本中有两种是鱼类,三种不是鱼类。

可建立的特征向量如下:

_data_set = [[1, 1, "yes"],[1, 1, "yes"],[1, 0, "no"],[0, 1, "no"],[0, 1, "no"]]_labels = ["no surfacing", "flippers"]

_labels储存的是特征的实际含义,在建立决策树时作为分类节点名称存在,no surfaciing就是不需要浮出水面是否可以生存。最后一列储存的是对应特征向量的标签。后续的代码中都遵循这一约定。

2、用ID3算法来构造决策树

ID3算法将信息增益做贪心算法来划分算法,总是挑选是的信息增益最大的特征来划分数据,使得数据更加有序。

2.1信息增益

熵:熵是信息的期望,一般表示信息的混乱、无序程度

信息的定义如下:

于是信息的期望,熵的定义为:

信息增益指的是熵减小的量,也就是,数据集变得有序了多少。

下面给出熵的计算代码,直接输入上面给出的数据集可以得到信息熵

# 计算香农熵
def calc_shannon_ent(dataset):n = len(dataset)label_counts = {}# 统计每个类别出现的次数for feature in dataset:label = feature[-1]if label not in label_counts:label_counts[label] = 0     # 创建该元素并清零label_counts[label] += 1entropy = 0for key in label_counts:p = float(label_counts[key]) / n  # 计算类概率,或者说类在所有数据中的比例entropy -= p * log(p, 2)return entropy

再次注意:特征向量最后一维是类别标签

2.2数据集划分

构造树的过程中,要将数据进行划分,为了方便,写一个子函数专门做数据划分,划分的原则是:挑出指定维度上和指定值相等的所有特征向量,并将该维去除后返回

# 在axis维度上对dataset进行划分,抽取axis维度上等于value的特征,这里没有用pandas,否则不需要这么麻烦
def splite_dataset(dataset, axis, value):splt_dset = []for f in dataset:if f[axis] == value:reduce_fv = f[:axis]reduce_fv.extend(f[axis+1:])splt_dset.append(reduce_fv)return splt_dset

2.3选择最好的划分特征

遍历每一个特征,尝试使用每一个特征划分数据集,并计算对应的信息增益,选择最大的那一个特征来划分数据。值得注意的是,这里并不是使用二分类划分,而是,对应的特征有多少个值就将数据集划分为几个子集。在海洋动物的例子中,只是恰好两个特征都只有两个值。

# 通过遍历所有的特征,求取熵最小的划分方式
# 返回划分数据最好的特征,和最大的信息增益
def min_entropy_split_feature(dataset):f_n = len(dataset[0]) - 1base_entropy = calc_shannon_ent(dataset)best_info_gain = 0.0#print("entropy calc:"+str(dataset))best_feature = -1for i in range(f_n):f_list = [feature[i] for feature in dataset]unique_values = set(f_list)new_entropy = 0.0for value in unique_values:sub_dataset = splite_dataset(dataset, i, value)pro = len(sub_dataset) / float(len(dataset))new_entropy += pro * calc_shannon_ent(sub_dataset)info_gain = base_entropy - new_entropy  # 信息增益是信息熵的减小量if info_gain > best_info_gain:best_info_gain = info_gainbest_feature = ireturn best_feature, best_info_gain

2.4递归构建决策树

2.3中给出了划分数据集的方法,可以使得数据局部整体上最有序,划分得到若干个子数据集中依然可以继续划分,使用同样的方法使得子数据集最有序,依次递归进行,直到最底层子数据集中只有一个类别

# 递归构建决策树
def create_tree(dataset, __labels):labels = __labels.copy()classlist = [f[-1] for f in dataset]# 只剩下一个类了,因此返回类名称if classlist.count(classlist[0]) == len(classlist):return classlist[0]# 数据集中只剩下最后一列了,也就是所有的特征都用完了,没法再向下分类了# 这时候如果数据集中有多个类,那就认为是出现最多的那个类# 实际中应该是,所给定的特征无法将数据进行完全分类导致的if len(dataset[0]) == 1:# print("******")return majority_cnt(classlist)bestfeature = min_entropy_split_feature(dataset)[0]# if bestfeature >= len(labels):#     print("**************index out of range")#     print(dataset)#     print(labels)#     print(bestfeature)bestf_label = labels[bestfeature]newtree = {bestf_label: {}}del labels[bestfeature]f_values = [f[bestfeature] for f in dataset]  # 找出bestfeature全部取值unique_f_values = set(f_values)for v in unique_f_values:sublabels = labels[:]_splitedtree = splite_dataset(dataset, bestfeature, v)# print("xxxxxxxxxxxxxx seperate:")# print("best fv:" + str(bestfeature) + " v:" + str(v))# print(_splitedtree)# print(labels)newtree[bestf_label][v] = create_tree(_splitedtree.copy(), sublabels)return newtree

上面还用了一个子函数,是当数据集只剩下一列(最后一列,也就是类别),但是无法完全分类,就返回剩下的数据集中出现最多的那个类别

# 计算数据集中的主要类别,这里计算是鱼的多还是不是鱼的多,其实就是判断yes多还是no多
# 其他应用中可能会出现多个类别标签,因此这是一个通用函数
def majority_cnt(classlist):classcount = {}for label in classlist:if label not in classcount.keys():  # 字典的键中不包含labelclasscount[label] = 0classcount[label] += 1# classcount.items()是以list形式返回字典的键值:dict_items([('yes', 2), ('no', 4)])# key中指定值获取函数,x[1]表示用键值对第二个参数来排序# reverse表示降序排序,默认是ascendingsorted_class_count = sorted(classcount.items(), key=lambda x: x[1], reverse=True)return sorted_class_count[0][0]  # 返回出现次数最多的类的标签

最后构建得到的决策树输入所示:

3、用决策树来做分类

上面构造了决策树,通过使用create_tree方法可以得到字典储存的决策树。输入一个新的特征向量,利用决策树,沿着树从上到下,可以得到分类。下面给出分类代码:

# 用构建好的决策树来进行分类
def classify(input_tree, feature_labels, test_fv):classlabel = "none"first_label = list(input_tree.keys())[0]  # 获取输入字典中的第一个键new_dict = input_tree[first_label]        #feature_index = feature_labels.index(first_label)  # 获取first_label是第几个特征for key in new_dict.keys():if test_fv[feature_index] == key:  # 注意,key是特征的值if type(new_dict[key]).__name__ == "dict":classlabel = classify(new_dict[key], feature_labels, test_fv)else:classlabel = new_dict[key]return classlabel

对于数据集来说,字典的根节点总是储存了本次划分数据集的特征,因此代码中总是先获取树根键值,然后根据该键获取特征编号index,在for循环中,遍历该特征的所有取值,计算得到子数据集进行递归,如果子数据集已经不是一个字典,则认为遍历已经到达最底层,最底层储存了类别标签,返回类别标签,完成分类。

4总结

构建决策树可以用来做分类,其他用途尚不清楚。使用了贪心法,每次划分都是选择信息增益最大的,推测这样不一定能得到全局最大增益。除了ID3算法构造决策树,较为流行的还有C4.5和CART算法,后面继续学习。

决策树做分类似乎只能对简单特征分类,如果出现长度、宽度、距离等浮点数据时候无法分类,暂时不知道怎么处理。

参考文献:《机器学习实战》

决策树(ID3算法)相关推荐

  1. 决策树---ID3算法

    决策树---ID3算法   决策树: 以天气数据库的训练数据为例. Outlook Temperature Humidity Windy PlayGolf? sunny 85 85 FALSE no ...

  2. 决策树ID3算法[分类算法]

    ID3分类算法的编码实现 1 <?php 2 /* 3 *决策树ID3算法(分类算法的实现) 4 */ 5 6 7 8 /* 9 10 *求信息增益Grain(S1,S2) 11 12 */ 1 ...

  3. 机器学习算法—决策树(ID3)算法

    机器学习--决策树(ID3)算法 1.决策树(ID3)算法 1.1 算法引入 我们首先以一个分类问题开始,假设我们有这样一份样本数据: 我们的目标是想通过色泽.根蒂.敲声.纹理.脐部.触感来判断这是不 ...

  4. 【Machine Learning in Action --3】决策树ID3算法

    1.简单概念描述 决策树的类型有很多,有CART.ID3和C4.5等,其中CART是基于基尼不纯度(Gini)的,这里不做详解,而ID3和C4.5都是基于信息熵的,它们两个得到的结果都是一样的,本次定 ...

  5. id3决策树_信息熵、信息增益和决策树(ID3算法)

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

  6. python决策树id3算法_python实现决策树ID3算法

    一.决策树概论 决策树是根据训练数据集,按属性跟类型,构建一棵树形结构.可以按照这棵树的结构,对测试数据进行分类.同时决策树也可以用来处理预测问题(回归). 二.决策树ID3的原理 有多种类型的决策树 ...

  7. 数据挖掘--决策树ID3算法(例题)

    决策树分类算法 决策树分类算法通常分为两个步骤:决策树生成和决策树修剪. 决策树生成算法的输入参数是一组带有类别标记的样本,输出是构造一颗决策树,该树可以是一棵二叉树或多叉树.二叉树的内部结点(非叶子 ...

  8. 【机器学习】决策树-ID3算法

    1.ID3算法 ID3算法利用信息增益进行特征的选择进行树的构建.信息熵的取值范围为0~1,值越大,越不纯,相反值越小,代表集合纯度越高.信息增益反映的是给定条件后不确定性减少的程度.每一次对决策树进 ...

  9. 决策树ID3算法手动实现

    1. ID3算法 决策树中每一个非叶结点对应着一个非类别属性,树枝代表这个属性的值.一个叶结点代表从树根到叶结点之间的路径对应的记录所属的类别属性值. 每一个非叶结点都将与属性中具有最大信息量的非类别 ...

  10. python决策树id3算法_决策树ID3算法预测隐形眼睛类型--python实现

    标签: 本节讲解如何预测患者需要佩戴的隐形眼镜类型. 1.使用决策树预测隐形眼镜类型的一般流程 (1)收集数据:提供的文本文件(数据来源于UCI数据库) (2)准备数据:解析tab键分隔的数据行 (3 ...

最新文章

  1. swift中字符串截取方法(substring)
  2. java连接pg_postgresql 入门(含java、scala连接代码)
  3. CornerNet-Lite:CornerNet粗暴优化,加速6倍还提点了 | BMVC 2020
  4. python元组和列表都支持的方法是_python_列表和元组
  5. 屏幕旋转的处理方法,实现视图位置的变化
  6. Linux下如何安装最新版本工具
  7. 无向图的深度优先遍历非递归_图算法总结
  8. 银行招聘笔试中行测和综合知识复习心得
  9. OSPFv3中LSA详解(二)——Router LSA详解
  10. U2000V1R2安装部署工作日报
  11. 友华PT921G光猫破解获取超级密码和更改桥接模式
  12. java 类中 serialversionuid 作用
  13. 双非计算机研究生要不要读,“双非”大学研究生,到底值不值得读?
  14. [ESP8266学习笔记]components_nvs 非易失性存储 Non-Volatile Storage(NVS),保存数据到flash
  15. os.path.dirname(path)
  16. 西安地铁行业投融资状况与发展策略建议报告2022版
  17. 如何用panda3d写一个游戏
  18. UltraRAM:在UltraScale+器件上集成嵌入式存储器
  19. JAVA基础之移位操作
  20. DNS域名称空间的组织方式

热门文章

  1. 东芝 rc100 linux,东芝RC100 M.2 NVMe固态硬盘HMB特性解读
  2. Hadoop和大数据:60款顶级大数据开源工具
  3. mac VMware fusion配置nat网络
  4. Jogging Trails 邮递员问题
  5. java 6面骰子_Java实现的简单掷骰子游戏示例
  6. 程序员如何阅读英文文档
  7. 测试5g网速的软件排行榜,2021网络测速app排行榜-手机网速测试软件推荐
  8. 查询iphone邮箱服务器,iPhone上的各种邮箱设置
  9. 计算机自带游戏在哪里,win10自带游戏,教您Win10纸牌游戏在哪
  10. win10系统玩部分老游戏时提示0xc0000022的解决方法.