机器学习 | 决策树详解与sklearn实战
一、sklearn概述
scikit-learn(又写作sklearn)是一个开源的Python机器学习工具包,通过NumPy、SciPy和Matplotlib等库实现高效的算法应用,涵盖了几乎所有主流机器学习算法。
在实际工程应用中,我们通常:
- 分析采集到的数据
- 根据数据特征选择适合的算法
- 在工具包中调用算法、调整参数
- 获取需要的信息
sklearn正是这样一个能帮助我们高效实现算法应用的工具包。
二、决策树工作原理
2.1 什么是决策树
决策树(Decision Tree)是一种非参数的有监督学习方法,能够从有特征和标签的数据中总结出决策规则,用树状图结构呈现,解决分类和回归问题。
2.2 决策树的核心概念
决策树由三种节点组成:
| 节点类型 | 描述 |
|---|---|
| 根节点 | 没有进边,有出边。包含最初的特征提问 |
| 中间节点 | 既有进边也有出边,进边只有一条,出边可以有多条 |
| 叶子节点 | 有进边,没有出边,每个叶子节点都是一个类别标签 |
父节点和子节点:两个相连的节点中,接近根节点的是父节点,另一个是子节点。
2.3 决策树要解决的两个核心问题
- 如何从数据表中找出最佳节点和最佳分枝?
- 如何让决策树停止生长,防止过拟合?
三、sklearn中的决策树
3.1 tree模块
sklearn中决策树的类都在tree模块下:
| 类 | 用途 |
|---|---|
tree.DecisionTreeClassifier |
分类树 |
tree.DecisionTreeRegressor |
回归树 |
tree.export_graphviz |
导出为DOT格式,画图专用 |
tree.ExtraTreeClassifier |
高随机版本的分类树 |
tree.ExtraTreeRegressor |
高随机版本的回归树 |
3.2 sklearn建模基本流程
python
from sklearn import tree
# 1. 导入模块
clf = tree.DecisionTreeClassifier()
# 2. 实例化
clf = clf.fit(X_train, y_train)
# 3. 用训练集数据训练模型
result = clf.score(X_test, y_test)
# 4. 导入测试集,从接口调用需要的信息
四、DecisionTreeClassifier 重要参数详解
4.1 criterion(不纯度计算方法)
作用:决定不纯度的计算方法,帮助找出最佳节点和最佳分枝。
决策树算法通过不纯度来衡量节点的质量。不纯度越低,决策树对训练集的拟合越好。sklearn提供两种选择:
| 参数值 | 计算方法 |
|---|---|
"gini" |
基尼系数(Gini Impurity) |
"entropy" |
信息熵(Entropy) |
公式:
- 基尼系数:Gini(t)=1−∑i=0c−1p(i∣t)2Gini(t) = 1 - \sum_{i=0}^{c-1}p(i|t)^2Gini(t)=1−∑i=0c−1p(i∣t)2
- 信息熵:Entropy(t)=−∑i=0c−1p(i∣t)log2p(i∣t)Entropy(t) = -\sum_{i=0}^{c-1}p(i|t)log_2p(i|t)Entropy(t)=−∑i=0c−1p(i∣t)log2p(i∣t)
选择建议:
| 场景 | 推荐 |
|---|---|
| 默认 | 基尼系数 |
| 数据维度很大,噪音很多 | 基尼系数 |
| 维度低,数据比较清晰 | 两者皆可 |
| 决策树拟合程度不够 | 信息熵 |
信息熵对不纯度更敏感,计算比基尼系数慢,但惩罚更强。高维数据或噪音多时容易过拟合。
4.2 random_state & splitter(随机性控制)
random_state:设置分枝中的随机模式参数
- 默认None,高维度时随机性更明显
- 输入任意整数,可以长出同一棵树,让模型稳定
splitter:控制分枝的随机程度
| 值 | 行为 |
|---|---|
"best" |
优先选择更重要的特征进行分枝 |
"random" |
更加随机,树更深更大 |
当预测模型会过拟合时,可用这两个参数降低过拟合可能性。
4.3 剪枝参数(防止过拟合)
在不加限制的情况下,决策树会生长到不纯度指标最优或没有更多特征可用,这样往往会导致过拟合------在训练集上表现好,但在测试集上表现糟糕。
max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉。
在高维度低样本量时非常有效,建议从=3开始尝试。
min_samples_leaf & min_samples_split
| 参数 | 作用 |
|---|---|
min_samples_leaf |
限定一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本 |
min_samples_split |
限定一个节点必须包含至少min_samples_split个训练样本才允许被分枝 |
建议从=5开始使用。如果类别不多的分类问题,=1通常就是最佳选择。
max_features
限制分枝时考虑的特征个数,超过限制个数的特征会被舍弃。
在不知道特征重要性的情况下强行设定可能导致模型学习不足。
min_impurity_decrease
限制信息增益的大小,信息增益小于设定数值的分枝不会发生。
4.4 目标权重参数(处理样本不平衡)
class_weight:对样本标签进行平衡,给少量标签更多权重。
场景:比如银行判断信用卡违约(是vs否 = 1%:99%),即使全预测成"否"正确率也有99%,这时需要调整权重。
min_weight_fraction_leaf :基于权重的剪枝参数,与class_weight配合使用。
五、重要属性和接口
属性
feature_importances_:查看各个特征对模型的重要性
python
clf.feature_importances_
[*zip(feature_name, clf.feature_importances_)]
四个核心接口
| 接口 | 功能 |
|---|---|
fit(X_train, y_train) |
训练模型 |
score(X_test, y_test) |
返回预测准确度 |
apply(X_test) |
返回每个测试样本所在的叶子节点索引 |
predict(X_test) |
返回每个测试样本的标签 |
python
# 训练和评估
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
# 查看特征重要性
clf.feature_importances_
# 预测
clf.apply(Xtest) # 返回叶子节点索引
clf.predict(Xtest) # 返回分类结果
六、实战:绘制决策树
python
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import graphviz
# 1. 导入数据
wine = load_wine()
# 2. 分训练集和测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(
wine.data, wine.target, test_size=0.3
)
# 3. 建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy", random_state=30)
clf = clf.fit(Xtrain, Ytrain)
# 4. 评估
score = clf.score(Xtest, Ytest)
# 5. 绘制决策树
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚',
'类黄酮','非黄烷类酚类','花青素','颜色强度',
'色调','od280/od315稀释葡萄酒','脯氨酸']
dot_data = tree.export_graphviz(
clf,
feature_names=feature_name,
class_names=["琴酒","雪莉","贝尔摩德"],
filled=True,
rounded=True
)
graph = graphviz.Source(dot_data)
graph
七、总结
决策树核心知识点
| 类别 | 内容 |
|---|---|
| 七个参数 | Criterion、random_state、splitter、max_depth、min_samples_leaf、max_features、min_impurity_decrease |
| 一个属性 | feature_importances_ |
| 四个接口 | fit、score、apply、predict |
超参数调优建议
通过学习曲线来判断最优参数------以超参数取值为横坐标,模型度量指标(score)为纵坐标绘制曲线。
调参没有绝对的答案,一切都要看数据本身。
不同数据集的模型选择
| 数据集类型 | 最擅长的模型 |
|---|---|
| 月亮型数据 | 最近邻算法、RBF支持向量机、高斯过程 |
| 环形数据 | 最近邻算法、高斯过程 |
| 对半分数据 | 朴素贝叶斯、神经网络、随机森林 |
八、剪枝策略
|
| 新增参数 | 说明 |
|---|---|
| min_samples_split | 节点分枝前的最小样本数门槛 |
| max_leaf_nodes | 限制最大叶子节点数 |
| min_impurity_split | 已废弃,用min_impurity_decrease替代 |
| presort | 是否预排序加速拟合 |
| max_depth | 限制树的最大深度,超过设定深度的树枝全部剪掉 |
python
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
,max_depth=3
,min_samples_leaf=10
,min_samples_split=10
)
clf = clf.fit(Xtrain, Ytrain)