决策树(DT)是最直观的机器学习算法,其可以根据一系列简单选择做出复杂决策。
DT 在运筹学和数据科学领域非常实用,其成功的原因在于它遵循与人类决策过程类似的过程。该过程基于流程图,其中每个节点都会对给定变量进行简单的二元决策,直到我们做出最终决策。
举个简单的例子:买一件 T 恤。如果我想买一件 T 恤,我可能会考虑几个变量,比如价格、品牌、尺码和颜色。所以我从预算开始做决定:
- 如果价格超过 30 美元,我不会买。否则我会买。
- 一旦找到低于 30 美元的商品,我希望它是我喜欢的品牌。如果是,我会继续做决定。
- 现在,它适合我吗?我的尺寸?如果适合,我们继续。
- 最后,如果 30 美元以下、品牌 X、尺码 S 的衬衫是黑色的,我会买它,否则,我可以继续寻找,或者以“我不会买它”结束我的决策过程。
决策树过程
这个过程非常合乎逻辑且简单,可以应用于所有类型的数据。该算法的缺点是它对数据集变化非常敏感,尤其是小数据集。因此,它很容易学习数据的微小差异并过度拟合你的机器学习模型。
DT 的这种特性可能对预测造成不小危害,但这如果用在探索性数据分析过程中将会非常出彩。
在这篇文章中,我们将学习如何利用 DT 的强大功能从数据中提取信息。
什么是 EDA?
探索性数据分析(EDA)是数据科学项目的一个阶段,我们获取数据集并探索其变量,尽可能多地了解对目标变量影响最大的因素。
在这个阶段,数据科学家希望了解数据、数据如何分布、是否存在错误或不完整,提取数据的第一手信息,并可视化并了解每个解释变量如何影响目标变量。
在流程中使用决策树
由于 DT 能够捕捉数据中最小的方差,因此使用它有助于理解变量之间的关系。由于我们只是在这里探索数据,因此我们不必非常小心地进行数据拆分或算法微调。我们只需运行 DT 即可获得最佳信息。
数据集
这里使用的数据集是学生表现数据集根据。
# 导入库
import pandas as pd
import seaborn as sns
sns.set_style()
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
from sklearn.tree import plot_tree
# 加载数据集
from ucimlrepo import fetch_ucirepo
# 获取数据集
student_performance = fetch_ucirepo(id = 320)
# 数据(作为 pandas 数据框)
X = student_performance.data.features
y = student_performance.data.targets
# 收集 X 和 Y 进行可视化
df = pd.concat([X,y], axis= 1 )
df.head( 3 )
图片
我们想要确定这些数据中的哪些变量对最终成绩的影响更大G3。
使用回归 DT 进行探索
failures现在构建一个 DT 来检查以及absences对studytime的影响G3。
# 要探索的列
cols = [ 'failures' , 'absences' , 'studytime' ]
# 分割 X 和 Y
X = df[cols]
y = df.G3
# 拟合决策树
dt = DecisionTreeRegressor().fit(X,y)
# 绘制 DT
plt.figure(figsize=( 20 , 10 ))
plot_tree(dt, filled= True , feature_names=X.columns, max_depth= 3 , fnotallow= 8 );
这是得出的决策树。
决策树
现在我们有了一个很好的可视化来了解我们列出的那些变量之间的关系。以下是我们可以从这棵树中获得的见解:
- 我们知道,对于每个框内第一行的条件,左边表示“是”,右边表示“否”。
- 不及格次数较少(< 0.5,或者说为零)的学生成绩较高。只需观察左侧每个框的值都高于右侧的值即可。
- 在所有没有不及格的学生中,不及格的学生的成绩studytime > 2.5更高。分数几乎高出一分。
- 没有不及格记录、studytime < 1.5缺勤次数少于 22 次的 学生比学习时间较少、缺勤次数较多的学生的期末成绩更高。
自由活动和外出频率
如果我们想根据学生的自由活动时间和外出频率来了解哪些学生的成绩更高,代码如下。
# 要探索的列
cols = [ 'freetime' , 'goout' ]
# 分割 X 和 Y
X = df[cols]
y = df.G3
# 拟合决策树
dt = DecisionTreeRegressor().fit(X,y)
# 绘制 DT
plt.figure(figsize=( 20 , 10 ))
plot_tree(dt, filled= True , feature_names=X.columns, max_depth= 3 , fnotallow= 10 );
决策树外出/空闲时间
变量goout和的freetime等级从 1= 非常低到 5= 非常高。请注意,那些不经常外出 (< 1.5) 且没有空闲时间 (<1.5) 的人的分数与那些经常外出 (>4.5) 且有相当多空闲时间的人的分数一样低。最好的分数来自那些在外出次数 > 1.5 和空闲时间在 1.5 到 2.5 范围内之间取得平衡的人。
使用分类 DT 进行探索
可以使用分类树算法进行相同的练习。逻辑和编码相同,但现在显示的结果值是预测的类,而不是值。让我们看一个简单的示例,使用另一个数据集,来自 Seaborn 包的Taxis 数据集,它带来了一组纽约市的出租车运行情况。
如果我们想探究运行总金额和付款方式之间的关系,下面是代码。
# 加载数据集
df = sns.load_dataset('taxis').dropna()
# 要探索的列
cols = ['total']
# 拆分 X 和 Y
X = df[cols]
y = df['payment']
# 拟合决策树
dt = DecisionTreeClassifier().fit(X,y)
# 绘制树
plt.figure(figsize=( 21 , 10 ))
plot_tree(dt, filled= True , feature_names=X.columns, max_depth= 3 ,
fnotallow= 10 , class_names=[ 'cash' , 'credit_card' ]);
出租车总费用与付款方式
只需目测结果树,我们就能发现较低的total金额更有可能以现金支付。低于 9.32 美元的总额一般以现金支付。
写在最后
在文我们学习了一种快速使用决策树来探索数据集中变量之间关系的方法。
这种算法可以快速捕捉最初不容易发现的模式。我们可以利用决策树的力量来找到数据的那些切分点,从而从中提取出重要的见解。
关于代码的简要说明:
在函数中plot_tree(),你可以设置使用该功能所需的级别数。你还可以在sklearn 的max_depthDT 实例中设置该超参数。这取决于你。使用它的优点是你可以快速测试许多不同的深度,而无需重新训练模型。plot_tree
plot_tree(dt,filled= True,feature_names=X.columns,max_depth=3)