动手学决策树算法
决策树算法简介
代码地址:https://github.com/ForceInjection/hands-on-ML/blob/main/nju_software/%E5%86%B3%E7%AD%96%E6%A0%91.ipynb
1. 决策树
1.1 什么是决策树
决策树是一种监督学习算法,广泛应用于分类和回归任务。它通过递归地分裂数据集,将数据分成越来越小的子集,直到达到某种停止条件。每个内部节点表示一个特征或属性,每个分支表示一个决策规则,每个叶节点表示一个类别或预测值。决策树的结构直观,易于理解和解释,因此在许多领域都有广泛应用。
1.2 决策树的结构
根节点:包含所有样本的初始节点。 内部节点:表示一个特征或属性的测试。 叶节点:表示一个类别或预测值。 分支:表示根据特征测试结果的决策路径。
1.3 决策树的构建过程
选择分裂特征:使用信息增益、基尼指数等指标选择最佳的分裂特征。 递归分裂:对每个子节点重复分裂过程,直到满足停止条件。 停止条件:所有样本属于同一类,或没有更多特征可以分裂,或达到预设的树深度。
1.4 决策树的优缺点
优点: 可解释性强,决策过程直观。 能够处理非线性关系。 对缺失值和异常值有一定的鲁棒性。 缺点: 容易过拟合,导致泛化能力下降。 对数据的小变化敏感,可能导致树结构的不稳定。
2. 信息熵
对于一个离散的随机变量 ,其概率分布为 ,信息熵 定义为:
其中, 是随机变量 取值为 的概率, 表示以2为底的对数。
2.1 信息熵的性质
非负性:信息熵总是非负的,即 。 对称性:信息熵对概率分布的顺序不敏感,即 与 的顺序无关。 最大值:当所有 相等时,信息熵达到最大值。对于 个等概率事件,最大信息熵为 。 最小值:当某个 且其他 时,信息熵达到最小值0。
2.2 信息熵的直观解释
信息熵可以理解为对随机变量的平均信息量的度量。例如,考虑一个公平的六面骰子,每个面的概率都是 。此时,信息熵为:
这表示掷一次骰子的平均信息量约为2.585比特。
2.3 信息熵的计算示例
假设有一个二分类问题,其中类别A的概率为0.7,类别B的概率为0.3。计算信息熵:
2.4 信息熵的物理意义
信息熵是衡量随机变量不确定性的指标。熵值越高,表示不确定性越大;熵值越低,表示不确定性越小。
3. 信息增益
信息增益(Information Gain)是信息熵的一个重要应用,用于衡量某个特征对减少不确定性的作用。信息增益定义为:
其中, 是随机变量 的信息熵, 是在已知特征 的条件下,随机变量 的条件信息熵。
3.1 信息增益的物理意义
信息增益衡量了某个特征对减少不确定性的作用。信息增益越大,表示该特征对分类的贡献越大。
3.2 信息增益的计算示例
假设有一个数据集,包含两个特征 和 ,以及目标变量 。计算特征 的信息增益:
计算根节点的信息熵 。 计算在已知特征 的条件下,目标变量 的条件信息熵 。 信息增益 。
4. 示例
4.1 数据集
以下是一个简单的数据集,用于预测是否玩高尔夫球。数据集包括天气(晴天、多云、下雨)和湿度(高、正常)两个特征,以及目标变量是否玩高尔夫球(是或否)。
4.2 决策树构建的过程
决策树的构建过程通常包括以下几个步骤:
计算根节点的信息熵。 计算每个特征的信息增益。 选择信息增益最大的特征作为分裂特征。 递归地对每个子节点重复上述步骤,直到所有样本都属于同一类或没有更多特征可以分裂。
4.3 决策树构建的过程(ID3 算法)
接下来,我们将使用 ID3 算法手工构建决策树。以下是详细的步骤:
4.3.1 计算根节点的信息熵
信息熵的公式为:
其中, 是类别 在数据集 中的比例。
在根节点中,数据集 包含 14 个样本,其中“是”的有 9 个,“否”的有 5 个。
4.3.2 计算每个特征的信息增益
信息增益的公式为:
4.3.2.1 计算“天气”的信息增益
“天气”有三种取值:晴天、多云、下雨。
晴天:有 5 个样本,其中“是”的有 2 个,“否”的有 3 个。
多云:有 4 个样本,全是“是”。
下雨:有 5 个样本,其中“是”的有 3 个,“否”的有 2 个。
加权平均熵:
“天气”的信息增益:
4.3.2.2 计算“湿度”的信息增益
“湿度”有两种取值:高、正常。
高:有 7 个样本,其中“是”的有 3 个,“否”的有 4 个。
正常:有 7 个样本,全是“是”。
加权平均熵:
“湿度”的信息增益:
4.3.3 选择信息增益最大的特征作为分裂特征
比较“天气”和“湿度”的信息增益:
“湿度”的信息增益更大,因此选择“湿度”作为根节点的分裂特征。
4.3.4 递归地对每个子节点重复上述步骤
4.3.4.1 子节点 1:湿度为“高”
在湿度为“高”的子节点中,有 7 个样本,其中“是”的有 3 个,“否”的有 4 个。
计算“天气”的信息增益:
晴天:有 3 个样本,全是“否”。
多云:有 1 个样本,是“是”。
下雨:有 3 个样本,全是“否”。
加权平均熵:
“天气”的信息增益:
选择“天气”作为分裂特征。
4.3.4.2 子节点 2:湿度为“正常”
在湿度为“正常”的子节点中,有 7 个样本,全是“是”。
由于所有样本都属于同一类,停止分裂。
4.4 决策树
根据上述步骤,构建的决策树如下:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line湿度/ \高 正常/ \天气 是/ | \晴天 多云 下雨否 是 否
4.5 总结
通过上述步骤,我们使用 ID3 算法手工构建了决策树。最终的决策树以“湿度”为根节点,根据湿度的取值进一步分裂,直到所有样本都属于同一类。
5. 参考文献
[1] Quinlan, J. R. (1986). Induction of Decision Trees. Machine Learning, 1(1), 81-106. [2] Mitchell, T. M. (1997). Machine Learning. McGraw-Hill.
6. 总结
决策树是一种直观且强大的监督学习算法,通过递归地分裂数据集来构建树结构。信息熵和信息增益是选择分裂特征的关键指标,能够有效减少不确定性,提高分类准确性。通过上述示例,我们详细展示了如何使用ID3算法构建决策树,希望对读者理解和应用决策树算法有所帮助。
7. 示例代码
7.1 Python 代码
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linefrom sklearn.tree import DecisionTreeClassifierfrom sklearn.preprocessing import LabelEncoderimport pandas as pdimport matplotlib.pyplot as pltfrom matplotlib import rcParamsfrom sklearn.tree import plot_treefrom sklearn.tree import export_textfrom matplotlib.text import Text# 配置 matplotlib 使用字体rcParams['font.sans-serif'] = ['Heiti TC']rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 创建数据集data = {'天气': ['晴天', '晴天', '晴天', '多云', '多云', '下雨', '下雨', '下雨', '晴天', '晴天', '多云', '多云', '下雨', '下雨'],'湿度': ['高', '高', '高', '高', '正常', '高', '正常', '正常', '正常', '正常', '高', '正常', '高', '正常'],'是否玩高尔夫球': ['否', '否', '是', '是', '是', '否', '是', '是', '是', '是', '是', '是', '否', '是']}# 将数据转换为 DataFramedf = pd.DataFrame(data)print(df.to_string(index=False))# 对特征进行编码le_weather = LabelEncoder()le_humidity = LabelEncoder()df['天气_encoded'] = le_weather.fit_transform(df['天气'])df['湿度_encoded'] = le_humidity.fit_transform(df['湿度'])# 特征和目标变量X = df[['天气_encoded', '湿度_encoded']] # 确保 X 是一个 DataFramey = df['是否玩高尔夫球']# 创建决策树分类器clf = DecisionTreeClassifier(criterion='entropy', random_state=42)# 训练模型clf.fit(X, y)# 打印决策树的结构plt.figure(figsize=(18, 12))tree_plot = plot_tree(clf, feature_names=['天气', '湿度'], class_names=['否', '是'], filled=True, rounded=True)# 遍历图中的每个文本元素并调整字体大小for t in plt.gca().get_children():if isinstance(t, Text):t.set_fontsize(18) # 设置字体大小为 10plt.show()# 通过文本打印决策树tree_rules = export_text(clf, feature_names=['天气', '湿度'])print("决策树文本结构:")print(tree_rules)# 预测新样本new_samples = [[le_weather.transform(['晴天'])[0], le_humidity.transform(['高'])[0]], # 晴天, 高[le_weather.transform(['晴天'])[0], le_humidity.transform(['正常'])[0]], # 晴天, 正常[le_weather.transform(['多云'])[0], le_humidity.transform(['高'])[0]], # 多云, 高[le_weather.transform(['多云'])[0], le_humidity.transform(['正常'])[0]], # 多云, 正常[le_weather.transform(['下雨'])[0], le_humidity.transform(['高'])[0]], # 下雨, 高[le_weather.transform(['下雨'])[0], le_humidity.transform(['正常'])[0]] # 下雨, 正常]# 将 new_samples 转换为 DataFrame,并设置列名new_samples_df = pd.DataFrame(new_samples, columns=['天气_encoded', '湿度_encoded'])# 使用 DataFrame 进行预测predictions = clf.predict(new_samples_df)print("预测结果:")for sample, prediction in zip(new_samples, predictions):print(f"天气: {le_weather.inverse_transform([sample[0]])[0]}, 湿度: {le_humidity.inverse_transform([sample[1]])[0]} → {prediction}")
7.2 运行结果
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line天气 湿度 是否玩高尔夫球晴天 高 否晴天 高 否晴天 高 是多云 高 是多云 正常 是下雨 高 否下雨 正常 是下雨 正常 是晴天 正常 是晴天 正常 是多云 高 是多云 正常 是下雨 高 否下雨 正常 是# 图见最后决策树文本结构:|--- 湿度 <= 0.50| |--- class: 是|--- 湿度 > 0.50| |--- 天气 <= 0.50| | |--- class: 否| |--- 天气 > 0.50| | |--- 天气 <= 1.50| | | |--- class: 是| | |--- 天气 > 1.50| | | |--- class: 否预测结果:天气: 晴天, 湿度: 高 → 否天气: 晴天, 湿度: 正常 → 是天气: 多云, 湿度: 高 → 是天气: 多云, 湿度: 正常 → 是天气: 下雨, 湿度: 高 → 否天气: 下雨, 湿度: 正常 → 是