在本单元中,您将使用 YDF (Yggdrasil 决策森林) 库来训练和解读决策树。
本单元的灵感来自 🧭 YDF 入门教程。
预赛
在研究数据集之前,请执行以下操作:
- 创建新的 Colab 笔记本。
- 在新的 Colab 笔记本中放置并执行以下代码行,以安装 YDF 库:
!pip install ydf -U
- 导入以下库:
import ydf import numpy as np import pandas as pd
Palmer 企鹅数据集
此 Colab 使用 Palmer Penguins 数据集,其中包含三种企鹅的尺寸测量数据:
- 下巴带
- Gentoo
- 阿德利
这是一个分类问题,目标是根据 Palmer's Penguins 数据集中的数据预测企鹅的种类。以下是企鹅:
图 16. 三种不同的企鹅。图片作者:@allisonhorst
以下代码调用 pandas 函数将 Palmer Penguins 数据集加载到内存中:
path = "https://storage.googleapis.com/download.tensorflow.org/data/palmer_penguins/penguins.csv"
dataset = pd.read_csv(path)
label = "species"
# Display the first 3 examples.
dataset.head(3)
下表展示了 Palmer Penguins 数据集中的前 3 个示例:
表 3. Palmer Penguins 中的前 3 个示例
物种 | 岛屿 | bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | 性别 | 年 | |
---|---|---|---|---|---|---|---|---|
0 | 阿德利 | Torgersen | 39.1 | 18.7 | 181.0 | 3750.0 | 男 | 2007 年 |
1 | 阿德利 | Torgersen | 39.5 | 17.4 | 186.0 | 3800.0 | 女性 | 2007 年 |
2 | 阿德利 | Torgersen | 40.3 | 18.0 | 195.0 | 3250.0 | 女性 | 2007 年 |
完整的数据集包含数值特征(例如 bill_depth_mm
)、分类特征(例如 island
)和缺失特征。与神经网络不同,决策森林原生支持所有这些特征类型,因此您无需进行独热编码、归一化或添加额外的 is_present 特征。
以下代码单元格将数据集拆分为训练集和测试集:
# Use the ~20% of the examples as the testing set
# and the remaining ~80% of the examples as the training set.
np.random.seed(1)
is_test = np.random.rand(len(dataset)) < 0.2
train_dataset = dataset[~is_test]
test_dataset = dataset[is_test]
print("Training examples: ", len(train_dataset))
# >> Training examples: 272
print("Testing examples: ", len(test_dataset))
# >> Testing examples: 72
使用默认超参数训练决策树
您可以使用 CART(分类与回归树)学习算法(也称为学习器)训练您的第一个决策树,而无需指定任何超参数。这是因为 ydf.CartLearner
学习器提供了良好的默认超参数值。在本课程的后续部分中,您将详细了解此类模型的工作原理。
model = ydf.CartLearner(label=label).train(train_dataset)
上述调用未指定要用作输入特征的列。因此,系统会使用训练集中的每个列。该调用也未指定输入特征的语义(例如,数值、分类、文本)。因此,系统会自动推断出特征语义。
调用 model.plot_tree()
以显示生成的决策树:
model.plot_tree()
在 Colab 中,您可以使用鼠标显示有关特定元素的详细信息,例如每个节点中的类别分布。
图 17. 使用默认超参数训练的决策树。
Colab 显示,根条件包含 243 个示例。不过,您可能还记得,训练数据集包含 272 个示例。其余 29 个示例已自动预留用于验证和树剪枝。
第一个条件用于测试 bill_depth_mm
的值。表 4 和表 5 显示了不同物种的似然性,具体取决于第一种条件的结局。
表 4. 如果 bill_depth_mm ≥
42.3
,不同物种的似然性
物种 | 可能性 |
---|---|
阿德利企鹅(红色) | 8% |
Gentoo(蓝色) | 58% |
下颌带(绿色) | 36% |
表 5. 不同物种的似然,如果 bill_depth_mm < 42.3
物种 | 可能性 |
---|---|
阿德利企鹅(红色) | 97% |
Gentoo(蓝色) | 2% |
下颌带(绿色) | 0% |
bill_depth_mm
是一个数值特征。因此,值 42.3 是使用具有数值特征的二元分类的精确拆分算法找到的。
如果 bill_depth_mm ≥ 42.3
为 True,则进一步测试 flipper_length_mm ≥ 207.5
是否能近乎完美地将 Gentoo 与 Gentoo+Adelie 分开。
以下代码提供了模型的训练准确率和测试准确率:
train_evaluation = model.evaluate(train_dataset)
print("train accuracy:", train_evaluation.accuracy)
# >> train accuracy: 0.9338
test_evaluation = model.evaluate(test_dataset)
print("test accuracy:", test_evaluation.accuracy)
# >> test accuracy: 0.9167
虽然很少见,但测试准确率有可能高于训练准确率。在这种情况下,测试集可能与训练集不同。 不过,由于训练和测试是随机拆分的,因此这里的情况并非如此。更可能的解释是,测试数据集非常小(只有 72 个示例),因此准确率估计值存在噪声。
在实践中,对于如此小的数据集,最好使用交叉验证,因为这样可以计算出更准确的评估指标值。不过,在此示例中,为了简单起见,我们将继续进行训练和测试。
改进模型超参数
该模型是使用默认超参数值训练的单个决策树。如需获得更准确的预测结果,您可以:
由于我们尚未了解随机森林和梯度提升树算法,并且由于示例数量太少而无法进行自动超参数调优,因此您将手动改进模型。
上图所示的决策树很小,包含 61 个示例的叶节点同时包含 Adelie 和 Chinstrap 标签。为什么算法没有进一步划分此叶节点?造成这种情况的原因可能有两种:
- 可能已达到每个叶的最小样本数(默认值为
min_examples=5
)。 - 树可能经过了划分,然后进行了剪枝以防止过拟合。
将示例数量下限减少为 1,然后查看结果:
model = ydf.CartLearner(label=label, min_examples=1).train(train_dataset)
model.plot_tree()
图 18. 使用 min_examples=1 训练的决策树。
包含 61 个示例的叶节点已多次进一步划分。
为了确定进一步划分节点是否有价值,我们在测试数据集上评估此新模型的质量:
print(model.evaluate(test_dataset).accuracy)
# >> 0.97222
模型质量有所提高,测试准确率从 0.9167 提高到了 0.97222。更改此超参数是个好主意。
决策森林预览
通过不断改进超参数,我们很可能可以达到完美的准确率。不过,我们可以训练一个更强大的模型(例如随机森林),看看效果是否更好,而不是采用这种手动流程。
model = ydf.RandomForestLearner(label=label).train(train_dataset)
print("Test accuracy: ", model.evaluate(test_dataset).accuracy)
# >> Test accuracy: 0.986111
随机森林的准确度高于我们的简单树。您将在接下来的页面中了解原因。
使用情况和限制
如前所述,单个决策树的质量通常不如现代机器学习方法,例如随机森林、梯度提升树和神经网络。不过,在以下情况下,决策树仍然很有用:
- 作为评估更复杂方法的简单且经济实惠的基准。
- 当模型质量和可解释性之间存在权衡时。
- 作为决策森林模型解释的代理,本课程稍后将对此进行探讨。