当前位置:   article > 正文

机器学习——决策树(DT)原理,ID3算法、C4.5算法python实现案例_id3 python

id3 python

目录

一、决策树简介

二、决策树构建

2.1构建方法

   2.2.1  ID3算法

   2.2.2  C4.5算法

   2.2.3  CART算法

2.2决定树的停止条件

2.3决策树剪枝

三、Python实现案例

创建数据集:

3.1  ID3算法

3.2  C4.5算法:

四、总结


一、决策树简介

         决策树是一种基于树状结构的机器学习算法,用于分类和回归任务。它通过一系列简单的问题或条件,逐步将数据集划分到不同的类别或值。每个内部节点表示一个特征/属性,每个分支代表一个可能的特征值,而每个叶节点表示一个类别或值。

        决策树易于理解和解释,适用于小型到中等规模的数据集,并且能够处理具有非线性关系的数据。常见的决策树算法包括ID3、C4.5、CART等。

二、决策树构建

2.1构建方法

   2.2.1  ID3算法

ID3(Iterative Dichotomiser 3)算法是由 Ross Quinlan 在 1986 年提出的,是一种基于信息增益的决策树构建算法。该算法通过选择能够产生最大信息增益的特征来进行节点的分裂,直到所有的数据点都属于同一类别或者达到了预定的停止条件,是决策树的一个经典的构造算法,内部使用:信息熵,信息增益,来进行构建:每次迭代选择信息最大的特征属性作为分割属性。
在ID3算法中:

1.节点纯度的度量用 “信息熵”

2.分裂特征的选择用的是信息增益度作为衡量指标

3.信息熵越低——确定性越高——有序——数据越纯

4.信息增益——以A特征分割后,信息熵减少的越多,那就以为和Gain越大,说明分裂后信息的信息熵更低,数据更纯。

信息熵(Entropy)计算公式:

信息条件熵(Conditional Entropy)计算公式:

信息增益(Information Gain)计算公式:

   2.2.2  C4.5算法

C4.5算法是ID3算法的改进版本,由 Ross Quinlan 在 1993 年提出。相比于ID3,C4.5算法使用信息增益比来选择特征,这使得它能够更好地处理具有不同数目属性值的特征。此外,C4.5还可以处理连续特征和缺失值。

相比于ID3,C4.5算法:

1.使用信息增益率来取代ID3算法中的信息增益,

2.在树的构造过程中会进行剪枝操作进行优化

3.能够自动完成对连续属性的离散化处理(可以对连续特征进行分裂)

4.C4.5构建的是多分支的决策树;

5.C4.5算法在选中分割属性的时候选择信息增益率最大的属性

信息增益率计算公式:

   2.2.3  CART算法

CART(classification and regression tree),分类回归树,它既可以用来解决分类问题也可以用来解决回归问题。

划分标准:使用使得gini系数最小的那个属性来划分样本。

基尼系数:(Gini不纯度)表示在样本集合中一个随机选中的样本被分错的概率。

注意:Gini系数越小表示集合中被选中的样本被分错的概率越小,也就是说集合的纯度越高,反之,集合越不纯。当集合中所有样本只有一个类时,基尼系数为0.

基尼指数计算公式:

对于CART算法:

1.CART与C4.5算法是非常相似的,但是CART支持预测连续的值(即回归)。

2.CART构建二叉树,而C4.5则不一定。显然由于二叉树的原因使得CART5不会出现ID3的问题(倾向于选择属性值多的属性来划分样本)

3.CART用训练集和交叉验证集不断地评估决策树的性能来修剪决策树,从而使训练误差和测试误差达到一个很好地平衡点。

2.2.4三种算法总结对比:

1. ID3、C4.5和CART算法均只适合在小规模数据集上使用
2. ID3、C4.5和CART算法都是单变量决策树
3. 当属性值取值比较多的时候,最好考虑C4.5算法,ID3得出的效果会比较差
4. 决策树分类一般情况只适合小数据量的情况(数据可以放内存)
5. CART算法是三种算法中最常用的一种决策树构建算法**(sklearn中仅支持CART:构造出来的是二叉树)
        三种算法的区别仅仅只是对于当前树的评价标准不同而已,ID3使用信息增益、C4.5使用信息增益率、CART使用基尼系数。

2.2决定树的停止条件

       在构建决策树时,需要设定一些条件来决定何时停止树的生长,以防止过拟合。常见的停止条件包括节点中的样本数量小于阈值、树的深度达到预设值或者信息增益小于阈值等。

2.3决策树剪枝

       剪枝即是删除一些最不可靠的分枝,用多个类的叶节点代替,以加快分类的速度和提高决策树正确分类新数据的能力。常用的剪枝方法有预剪枝和后剪枝:

预剪枝就是提早结束决策树的构造过程,通过选取一个阈值判断树的构造是否停止,因为适当的阈值很难界定,所以预剪枝存在危险,不能保证树的可靠性;

后剪枝是在决策树构造完毕后得到一棵完整的树再进行剪枝,通常的思想是对每个树节点进行错误估计,通过与其子树的错误估计的比较,来判断子树的裁剪,如果子树的错误估计较大,则被剪枝,最后用一个独立的测试集去评估剪枝后的准确率,以此得到估计错误率最小的决策树。

三、Python实现案例

创建数据集:

  1. # 创建示例数据集
  2. dataset = [
  3. ['青年', '否', '否', '一般', '否'],
  4. ['青年', '否', '否', '好', '否'],
  5. ['青年', '是', '否', '好', '是'],
  6. ['青年', '是', '是', '一般', '是'],
  7. ['青年', '否', '否', '一般', '否'],
  8. ['中年', '否', '否', '一般', '否'],
  9. ['中年', '否', '否', '好', '否'],
  10. ['中年', '是', '是', '好', '是'],
  11. ['中年', '否', '是', '非常好', '是'],
  12. ['中年', '否', '是', '非常好', '是'],
  13. ['老年', '否', '是', '非常好', '是'],
  14. ['老年', '否', '是', '好', '是'],
  15. ['老年', '是', '否', '好', '是'],
  16. ['老年', '是', '否', '非常好', '是'],
  17. ['老年', '否', '否', '一般', '否']
  18. ]

3.1  ID3算法

  1. import numpy as np
  2. def entropy(y):
  3. # 统计每个类别的出现次数
  4. _, counts = np.unique(y, return_counts=True)
  5. # 计算信息熵
  6. probabilities = counts / len(y)
  7. entropy = -np.sum(probabilities * np.log2(probabilities))
  8. return entropy
  9. def find_best_split(X, y):
  10. best_entropy = np.inf
  11. best_feature_idx = None
  12. best_threshold = None
  13. # 对每个特征进行遍历
  14. for feature_idx in range(X.shape[1]):
  15. thresholds = np.unique(X[:, feature_idx])
  16. # 对每个可能的阈值进行遍历
  17. for threshold in thresholds:
  18. left_indices = np.where(X[:, feature_idx] <= threshold)[0]
  19. right_indices = np.where(X[:, feature_idx] > threshold)[0]
  20. # 计算左右子集的信息熵
  21. left_entropy = entropy(y[left_indices])
  22. right_entropy = entropy(y[right_indices])
  23. # 计算加权信息熵
  24. weighted_entropy = (len(left_indices) / len(y)) * left_entropy + \
  25. (len(right_indices) / len(y)) * right_entropy
  26. # 如果加权信息熵小于当前最优值,则更新最优值
  27. if weighted_entropy < best_entropy:
  28. best_entropy = weighted_entropy
  29. best_feature_idx = feature_idx
  30. best_threshold = threshold
  31. return best_feature_idx, best_threshold
  32. class Node:
  33. def __init__(self, predicted_class):
  34. self.predicted_class = predicted_class
  35. self.feature_index = 0
  36. self.threshold = 0
  37. self.left = None
  38. self.right = None
  39. def build_tree(X, y):
  40. # 如果所有样本属于同一类别,则返回叶节点
  41. if len(set(y)) == 1:
  42. return Node(predicted_class=y[0])
  43. # 如果样本中只剩下一个特征,则返回叶节点,预测类别为样本中最频繁出现的类别
  44. if X.shape[1] == 1:
  45. return Node(predicted_class=np.bincount(y).argmax())
  46. # 寻找最优划分特征及阈值
  47. best_feature_idx, best_threshold = find_best_split(X, y)
  48. # 根据最优划分特征和阈值划分数据集
  49. left_indices = np.where(X[:, best_feature_idx] <= best_threshold)[0]
  50. right_indices = np.where(X[:, best_feature_idx] > best_threshold)[0]
  51. # 如果划分后的数据集为空,则返回叶节点,预测类别为样本中最频繁出现的类别
  52. if len(left_indices) == 0 or len(right_indices) == 0:
  53. return Node(predicted_class=np.bincount(y).argmax())
  54. # 递归构建左子树和右子树
  55. left_subtree = build_tree(X[left_indices], y[left_indices])
  56. right_subtree = build_tree(X[right_indices], y[right_indices])
  57. # 创建当前节点
  58. node = Node(predicted_class=None)
  59. node.feature_index = best_feature_idx
  60. node.threshold = best_threshold
  61. node.left = left_subtree
  62. node.right = right_subtree
  63. return node
  64. def predict(node, sample):
  65. if node.predicted_class is not None:
  66. return node.predicted_class
  67. if sample[node.feature_index] <= node.threshold:
  68. return predict(node.left, sample)
  69. else:
  70. return predict(node.right, sample)
  71. def test(tree, X_test):
  72. predictions = []
  73. for sample in X_test:
  74. predictions.append(predict(tree, sample))
  75. return predictions
  76. # 将数据集转换为数组
  77. dataset_array = np.array(dataset)
  78. X = dataset_array[:, :-1] # 特征
  79. y = dataset_array[:, -1] # 标签
  80. # 构建决策树
  81. tree = build_tree(X, y)
  82. # 测试数据
  83. test_data = [
  84. ['青年', '否', '否', '一般'],
  85. ['老年', '是', '否', '好'],
  86. ['中年', '否', '是', '非常好']
  87. ]
  88. # 进行预测
  89. predictions = test(tree, test_data)
  90. # 进行测试并输出结果
  91. print("测试数据:")
  92. for i, data in enumerate(test_data):
  93. print(f"样本 {i+1}: {data},预测结果: {predictions[i]}")
  94. # 计算准确率
  95. ground_truth = ['否', '是', '是'] # 测试数据的真实标签
  96. correct_predictions = sum(1 for true, pred in zip(ground_truth, predictions) if true == pred)
  97. accuracy = correct_predictions / len(ground_truth) * 100
  98. print(f"\n准确率: {accuracy:.2f}%")

运行结果:

3.2  C4.5算法:

计算数据集的熵:

  1. # 计算数据集在某个特征上的条件熵
  2. def calculate_conditional_entropy(data, feature_index):
  3. feature_values = set([row[feature_index] for row in data])
  4. conditional_entropy = 0
  5. for value in feature_values:
  6. subset = [row for row in data if row[feature_index] == value]
  7. prob = len(subset) / len(data)
  8. conditional_entropy += prob * calculate_entropy(subset)
  9. return conditional_entropy

计算数据集在某个特征上的条件熵:

  1. # 计算数据集在某个特征上的条件熵
  2. def calculate_conditional_entropy(data, feature_index):
  3. feature_values = set([row[feature_index] for row in data])
  4. conditional_entropy = 0
  5. for value in feature_values:
  6. subset = [row for row in data if row[feature_index] == value]
  7. prob = len(subset) / len(data)
  8. conditional_entropy += prob * calculate_entropy(subset)
  9. return conditional_entropy

计算信息增益:

  1. def calculate_information_gain(data, feature_index):
  2. entropy = calculate_entropy(data)
  3. conditional_entropy = calculate_conditional_entropy(data, feature_index)
  4. information_gain = entropy - conditional_entropy
  5. return information_gain

选择最佳划分特征:

  1. def choose_best_feature(data):
  2. num_features = len(data[0]) - 1
  3. best_feature_index = -1
  4. best_information_gain = 0
  5. for i in range(num_features):
  6. information_gain = calculate_information_gain(data, i)
  7. if information_gain > best_information_gain:
  8. best_information_gain = information_gain
  9. best_feature_index = i
  10. return best_feature_index

递归构建决策树:

  1. # 递归构建决策树
  2. def build_decision_tree(data, features):
  3. labels = [row[-1] for row in data]
  4. # 如果所有实例都属于同一类别,则返回该类别
  5. if len(set(labels)) == 1:
  6. return labels[0]
  7. # 如果没有特征可用或者数据集为空,则返回出现次数最多的类别
  8. if len(data) == 0 or len(features) == 0:
  9. return max(set(labels), key=labels.count)
  10. # 选择最佳划分特征
  11. best_feature_index = choose_best_feature(data)
  12. best_feature = features[best_feature_index]
  13. decision_tree = {best_feature: {}}
  14. # 删除已选特征
  15. del(features[best_feature_index])
  16. feature_values = set([row[best_feature_index] for row in data])
  17. for value in feature_values:
  18. subset = [row for row in data if row[best_feature_index] == value]
  19. decision_tree[best_feature][value] = build_decision_tree(subset, features[:])
  20. return decision_tree

测试决策树模型:

  1. # 测试决策树模型
  2. def predict(decision_tree, instance):
  3. if isinstance(decision_tree, dict):
  4. root = list(decision_tree.keys())[0]
  5. subtree = decision_tree[root]
  6. root_index = feature_names.index(root)
  7. root_value = instance[root_index]
  8. if root_value in subtree:
  9. return predict(subtree[root_value], instance)
  10. else:
  11. return "Unknown"
  12. else:
  13. return decision_tree
  14. # 测试数据集
  15. test_data = [
  16. ['青年', '否', '否', '一般'],
  17. ['中年', '是', '是', '好'],
  18. ['老年', '否', '是', '好']
  19. ]
  20. # 特征名称
  21. feature_names = ['年龄', '有工作', '有自己的房子', '信贷情况']
  22. # 构建决策树
  23. decision_tree = build_decision_tree(dataset, feature_names[:])
  24. # 输出决策树
  25. print("决策树:", decision_tree)
  26. # 测试决策树模型
  27. for instance in test_data:
  28. prediction = predict(decision_tree, instance)
  29. print("测试实例:", instance, " 预测结果:", prediction)

运行结果:


四、总结

        作为机器学习中的一大类模型,树模型一直以来都颇受学界和业界的重视。目前无论是各大比赛各种大杀器的XGBoost、lightgbm、还是像随机森林、AdaBoost等典型集成学习模型,都是以决策树模型为基础的。传统的经典决策树算法包括ID3算法、C4.5算法以及GBDT的基分类器CART算法。

        三大经典决策树算法最主要的区别是其特征选择的准则不同。ID3算法选择特征的依据是信息增益、C4.5是信息增益比,而CART则是基尼指数。作为一种基础的分类和回归方法,决策树可以有以下两种理解方法:可以认为是if-then的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。

        决策树学习算法通常是一个递归地选择最优特征, 并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。开始,构建根结点,将所有训练数据都放在根结点。选择一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。如果这些子集已经能够被基本正确分类,那么构建叶结点,并将这些子集分到所对应的叶结点中去,如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的结点。如此递归地进行下去,直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。最后每个子集都被分到叶结点上,即都有了明确的类。这就生成了一棵决策树。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/666586
推荐阅读
相关标签
  

闽ICP备14008679号