赞
踩
一、决策树的基本认识
决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。
二、算法简介
决策树是一种经典的机器学习算法,它通过对数据集进行递归地分割,构建一个树形结构,每个节点代表一个属性测试,每个分支代表一个测试结果,叶子节点表示最终的决策结果或类别。ID3、C4.5和CART是三种常见的决策树算法,下面简要介绍它们:
ID3(Iterative Dichotomiser 3):
C4.5:
CART(Classification and Regression Trees):
这三种算法都是基于贪心策略构建决策树,它们在属性选择、处理缺失值、处理连续值等方面有所不同,适用于不同的数据情况和任务需求。
三、ID3算法
让我们考虑一个简单的二元分类数据集,关于天气状况以及是否适合打高尔夫球。
计算整个数据集的熵:
根据“Play”和“Don't Play”的比例,计算整个数据集的熵。这表示了数据集的不确定性或混乱程度。计算每个特征的信息增益:
针对每个特征(Outlook、Temperature、Humidity、Wind),计算在该特征条件下数据集的熵,并计算信息增益。信息增益表示了在特征条件下对数据集的分类带来的纯度提升。选择最佳分裂特征:
从所有特征中选择具有最高信息增益的特征作为节点分裂特征。递归构建决策树:
以选择的分裂特征为节点,将数据集划分成子集,并对每个子集重复上述过程,直到满足停止条件为止。通过计算每个特征的信息增益,我们可以选择具有最大信息增益的特征作为节点进行分裂。这样逐步构建决策树,直到满足停止条件(如达到最大深度或节点样本数少于阈值)。这就是ID3算法的基本过程。
以下是python代码实现:
- import pandas as pd
- from sklearn import tree
- from sklearn.model_selection import train_test_split
- from sklearn.metrics import accuracy_score
- import matplotlib.pyplot as plt
-
- # 创建数据集
- data = {
- 'Weather': ['Sunny', 'Sunny', 'Overcast', 'Rain', 'Rain', 'Rain', 'Overcast', 'Sunny', 'Sunny', 'Rain', 'Sunny', 'Overcast', 'Overcast', 'Rain'],
- 'Temperature': ['Hot', 'Hot', 'Hot', 'Mild', 'Cool', 'Cool', 'Cool', 'Mild', 'Cool', 'Mild', 'Mild', 'Mild', 'Hot', 'Mild'],
- 'Humidity': ['High', 'High', 'High', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'High'],
- 'Wind': ['Weak', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Strong'],
- 'Play Golf': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No']
- }
-
- df = pd.DataFrame(data)
-
- # 将分类特征转换为数字
- df_encoded = pd.get_dummies(df[['Weather', 'Temperature', 'Humidity', 'Wind']])
-
- # 分割数据集
- X = df_encoded
- y = df['Play Golf'].apply(lambda x: 1 if x == 'Yes' else 0)
-
- X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
-
- # 创建决策树分类器(使用entropy作为分裂准则,这类似于ID3)
- clf = tree.DecisionTreeClassifier(criterion='entropy')
-
- # 训练决策树
- clf.fit(X_train, y_train)
-
- # 预测
- y_pred = clf.predict(X_test)
-
- # 测试准确度
- accuracy = accuracy_score(y_test, y_pred)
-
- print(f"Test accuracy: {accuracy:.2%}")
-
- # 绘制决策树
- plt.figure(figsize=(12, 8))
- tree.plot_tree(clf, feature_names=list(X.columns), class_names=['No', 'Yes'], filled=True, fontsize=10)
- plt.show()

运行结果:
四、C4.5算法
同样以上述数据集为例。
计算整个数据集的熵:
根据“Play”和“Don't Play”的比例,计算整个数据集的熵。这表示了数据集的不确定性或混乱程度。计算每个特征的信息增益:
针对每个特征(Outlook、Temperature、Humidity、Wind),计算在该特征条件下数据集的熵,并计算信息增益。信息增益表示了在特征条件下对数据集的分类带来的纯度提升。选择最佳分裂特征:
从所有特征中选择具有最高信息增益的特征作为节点分裂特征。递归构建决策树:
以选择的分裂特征为节点,将数据集划分成子集,并对每个子集重复上述过程,直到满足停止条件为止。以下是python代码实现:
- from math import log
-
- def entropy(data):
- # 计算数据集的熵
- total_samples = len(data)
- label_counts = {}
- for sample in data:
- label = sample[-1]
- if label not in label_counts:
- label_counts[label] = 0
- label_counts[label] += 1
- entropy = 0
- for label in label_counts:
- probability = label_counts[label] / total_samples
- entropy -= probability * log(probability, 2)
- return entropy
-
- def split_data(data, feature_index):
- # 根据特征将数据集划分成子集
- split_data = {}
- for sample in data:
- value = sample[feature_index]
- if value not in split_data:
- split_data[value] = []
- split_data[value].append(sample)
- return split_data
-
- def information_gain(data, feature_index):
- # 计算特征的信息增益
- total_entropy = entropy(data)
- split_data_dict = split_data(data, feature_index)
- new_entropy = 0
- for value in split_data_dict:
- value_samples = split_data_dict[value]
- probability = len(value_samples) / len(data)
- new_entropy += probability * entropy(value_samples)
- information_gain = total_entropy - new_entropy
- return information_gain
-
- def intrinsic_value(data, feature_index):
- # 计算特征的固有值
- split_data_dict = split_data(data, feature_index)
- iv = 0
- for value in split_data_dict:
- probability = len(split_data_dict[value]) / len(data)
- iv -= probability * log(probability, 2)
- return iv
-
- def gain_ratio(data, feature_index):
- # 计算特征的信息增益比
- ig = information_gain(data, feature_index)
- iv = intrinsic_value(data, feature_index)
- gain_ratio = ig / iv if iv != 0 else 0
- return gain_ratio
-
- def choose_best_feature(data, features):
- # 选择信息增益比最高的特征作为节点分裂特征
- best_feature_index = -1
- best_gain_ratio = -1
- for idx, feature in enumerate(features):
- if feature == 'Play': # 最后一列是标签,跳过
- continue
- ratio = gain_ratio(data, idx)
- if ratio > best_gain_ratio:
- best_gain_ratio = ratio
- best_feature_index = idx
- return best_feature_index
-
- def majority_class(labels):
- # 返回子集中样本数最多的类别
- label_counts = {}
- for label in labels:
- if label not in label_counts:
- label_counts[label] = 0
- label_counts[label] += 1
- majority_label = max(label_counts, key=label_counts.get)
- return majority_label
-
- def build_tree(data, features):
- labels = [sample[-1] for sample in data]
- if len(set(labels)) == 1:
- return labels[0] # 所有样本属于同一类别,返回该类别
- if len(data[0]) == 1:
- return majority_class(labels) # 所有特征已经用完,返回子集中样本数最多的类别
- best_feature_index = choose_best_feature(data, features)
- best_feature = features[best_feature_index]
- decision_tree = {best_feature: {}}
- del features[best_feature_index]
- split_data_dict = split_data(data, best_feature_index)
- for value in split_data_dict:
- value_samples = split_data_dict[value]
- decision_tree[best_feature][value] = build_tree(value_samples, features[:])
- return decision_tree
-
- dataset = [
- ['Sunny', 85, 85, 'Weak', 'No'],
- ['Sunny', 80, 90, 'Strong', 'No'],
- ['Overcast', 83, 78, 'Weak', 'Yes'],
- ['Rain', 70, 96, 'Weak', 'Yes'],
- ['Rain', 68, 80, 'Weak', 'Yes'],
- ['Rain', 65, 70, 'Strong', 'No'],
- ['Overcast', 64, 65, 'Strong', 'Yes'],
- ['Sunny', 72, 95, 'Weak', 'No'],
- ['Sunny', 69, 70, 'Weak', 'Yes'],
- ['Rain', 75, 80, 'Weak', 'Yes'],
- ['Sunny', 75, 70, 'Strong', 'Yes'],
- ['Overcast', 72, 90, 'Strong', 'Yes'],
- ['Overcast', 81, 75, 'Weak', 'Yes'],
- ['Rain', 71, 80, 'Strong', 'No']
- ]
- headers = ['Outlook', 'Temperature', 'Humidity', 'Wind', 'Play']
-
- decision_tree = build_tree(dataset, headers[:-1]) # 构建决策树
- print(decision_tree)

运行结果:
{'Temperature': {85: 'No', 80: 'No', 83: 'Yes', 70: 'Yes', 68: 'Yes', 65: 'No', 64: 'Yes', 72: {'Outlook': {'Sunny': 'No', 'Overcast': 'Yes'}}, 69: 'Yes', 75: 'Yes', 81: 'Yes', 71: 'No'}}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。