菜菜 ML:决策树实战
3531 字约 12 分钟
2026-05-20
scikit-learn课堂第一期:sklearn入门 & 决策树在sklearn中的实现
开发环境要求
我的开发环境是 Jupyter lab,所用的库和版本参考:
- Python 3.7.1(你的版本至少要3.4以上)
- Scikit-learn 0.20.0(你的版本至少要0.19)
- Graphviz 0.8.4(没有画不出决策树哦,安装代码
conda install python-graphviz) - Numpy 1.15.3
- Pandas 0.23.4
- Matplotlib 3.0.1
- SciPy 1.1.0
sklearn入门
scikit-learn(又写作sklearn)是一个开源的基于python语言的机器学习工具包。它通过 NumPy、SciPy 和 Matplotlib 等 python 数值计算的库实现高效的算法应用,并且涵盖了几乎所有主流机器学习算法。
在工程应用中,用 python 手写代码来从头实现一个算法的可能性非常低,这样不仅耗时耗力,还不一定能够写出构架清晰,稳定性强的模型。更多情况下,是分析采集到的数据,根据数据特征选择适合的算法,在工具包中调用算法,调整算法的参数,获取需要的信息,从而实现算法效率和效果之间的平衡。而 sklearn,正是这样一个可以帮助我们高效实现算法应用的工具包。
决策树
1. 概述
1.1 决策树是如何工作的
决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。决策树算法容易理解,适用各种数据,在解决各种问题时都有良好表现,尤其是以树模型为核心的各种集成算法,在各个行业和领域都有广泛的应用。
关键概念:节点
- 根节点:没有进边,有出边。包含最初的,针对特征的提问。
- 中间节点:既有进边也有出边,进边只有一条,出边可以有很多条。都是针对特征的提问。
- 叶子节点:有进边,没有出边,每个叶子节点都是一个类别标签。
- 子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另一个是子节点。
1.2 sklearn中的决策树
模块 sklearn.tree 中的决策树类:
tree.DecisionTreeClassifier- 分类树tree.DecisionTreeRegressor- 回归树tree.export_graphviz- 将生成的决策树导出为DOT格式,画图专用tree.ExtraTreeClassifier- 高随机版本的分类树tree.ExtraTreeRegressor- 高随机版本的回归树
sklearn建模的基本流程
基本建模流程如下:
:
1%E5%86%B3%E7%AD%96%E6%A0%91/image.png
from sklearn import tree # 导入需要的模块
clf = tree.DecisionTreeClassifier() # 实例化
clf = clf.fit(X_train,y_train) # 用训练集数据训练模型
result = clf.score(X_test,y_test) # 导入测试集,从接口中调用需要的信息2. DecisionTreeClassifier与红酒数据集
class sklearn.tree.DecisionTreeClassifier (
criterion=’gini’,
splitter=’best’,
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
class_weight=None,
presort=False
)2.1 重要参数
2.1.1 criterion
为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法。对分类树来说,衡量这个"最佳"的指标叫做"不纯度"。通常来说,不纯度越低,决策树对训练集的拟合越好。
sklearn提供了两种选择:
- 输入"entropy",使用信息熵(Entropy)
- 输入"gini",使用基尼系数(Gini Impurity)
数学表达式:
- Entropy(t)=−∑p(i∣t)log2p(i∣t)
- Gini(t)=1−∑i=1c−1p(i∣t)2
其中t代表给定的节点,i代表标签的任意分类,p(i|t)代表标签分类i在节点t上所占的比例。
:
1%E5%86%B3%E7%AD%96%E6%A0%91/image%201.png
2.1.2 random_state & splitter
random_state用来设置分枝中的随机模式的参数,默认None。在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现。splitter也是用来控制决策树中的随机选项的:- 输入"best":决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝
- 输入"random":决策树在分枝时会更加随机
2.1.3 剪枝参数
主要的剪枝参数包括:
max_depth:限制树的最大深度min_samples_leaf:限定叶子节点最少的样本数min_samples_split:限定分枝最少的样本数max_features:限制分枝时考虑的特征个数,超过该特征都会被舍去min_impurity_decrease:限制信息增益的大小,信息增益小于设定数值的分枝不会发生。这是在0.19版本中更新的功能,在0.19版本之前时使用min_impurity_split。
确认最优的剪枝参数
这时候,我们就要使用确定超参数的曲线来进行判断了,继续使用我们已经训练好的决策树模型clf。超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。
2.1.4 目标权重参数
class_weight:完成样本标签平衡的参数min_weight_fraction_leaf:基于权重的剪枝参数
2.2 重要属性和接口
重要属性:
feature_importances_:能够查看各个特征对模型的重要性
常用接口:
fit:训练模型score:评分函数apply:返回每个测试样本所在的叶子节点索引predict:返回预测结果
3. DecisionTreeRegressor
回归树的基本结构:(和分类树一模一样)
python
Copy
class sklearn.tree.DecisionTreeRegressor(
criterion='mse',
splitter='best',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
presort=False
)几乎所有参数、属性及接口都和分类树一模一样。需要注意的是,在回归树中,没有标签分布是否均衡的问题,因此没有class_weight这样的参数。
3.1 重要参数,属性及接口
criterion(衡量分枝质量的指标)
回归树处理连续数据
回归树支持的标准有三种:
- 输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失
- 输入"friedman_mse"使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
- 输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失
其中MSE的计算公式:
MSE=N1∑(fi−yi)2
- N是样本数量
- i是每一个数据样本
- fi是模型回归出值
- yi是样本点i实际的数值标签
简单看看回归树是怎样工作的
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
boston = load_boston()
regressor = DecisionTreeRegressor(random_state=0)
cross_val_score(
regressor,
boston.data,
boston.target,
cv=10,
scoring = "neg_mean_squared_error"#默认是R方,通常用neg_mean_squared_error
)
#交叉验证cross_val_score的用法交叉验证是用来观察模型的稳定性的一种方法,我们将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量。
3.2 实例:一维回归的图像绘制
示例代码:
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# 创建随机数据
rng = np.random.RandomState(1)
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))
# 创建回归树模型
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
# 预测
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)4. 实例:泰坦尼克号幸存者的预测
基本步骤:
- 导入所需要的库
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt读取数据集:
#使用read.csv data = pd.read_csv(r"C:\work\learnbetter\micro-class\week 1 DT\data\data.csv",index_col = 0) #发现找到数据标签是Survived #探索数据 data.info() #可以看到有多少缺失值,每一个column都是什么type <class 'pandas.core.frame.DataFrame'> Index: 891 entries, 1 to 891 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Survived 891 non-null int64 1 Pclass 891 non-null int64 2 Name 891 non-null object 3 Sex 891 non-null object 4 Age 714 non-null float64 5 SibSp 891 non-null int64 6 Parch 891 non-null int64 7 Ticket 891 non-null object 8 Fare 891 non-null float64 9 Cabin 204 non-null object 10 Embarked 889 non-null object dtypes: float64(2), int64(4), object(5) memory usage: 83.5+ KB #可以看到年龄是有缺失值的,缺失值需要处理,总共891个数字 data.head(n) #可以有效查看前多少行数据预处理
- 删除缺失值过多的列
- 填补缺失值
- 将分类变量转换为数值型变量
#1. 筛选特征,是不是每一个特征都对结果有用 #Cabin没有什么用,缺失值太多了,直接删掉 data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1) #inplace=True删除掉了之后会自动覆盖原表,不然需要写data=data.drop() #2.处理缺失值 #根据判断年龄比较重要,老人和小孩会先上救生艇 #查看这些人的年龄 data["Age"] #利用平均值填补空缺值,也可以用中值,随机森林,0等填补 data["Age"] = data["Age"].fillna(data["Age"].mean()) #有的缺失的比较少,只要有缺失值的行就删掉: data = data.dropna() #3. 将三分类变量转换为数值型变量 #取出来,删掉所有重复值 data["Embarked"].unique() #换成数字: labels = data["Embarked"].unique().tolist() #特征量不能超过十个,而且是没有联系的。 data["Embarked"] = data["Embarked"].apply(lambda x: labels.index(x)) #astype能够将一个pandas对象转换为某种类型,和apply(int(x))不同,astype可以将文本类转换为数字,用这个方式可以很便捷地将二分类特征转换为0~1 data["Sex"] = (data["Sex"]== "male").astype("int")建立模型并调参
#创建横纵坐标: X = data.iloc[:,data.columns != "Survived"] y = data.iloc[:,data.columns == "Survived"] #除了survived都是x,y就是survived那一列 #把训练数据分成训练集和测试集 from sklearn.model_selection import train_test_split Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3) #修正测试集和训练集的索引 for i in [Xtrain, Xtest, Ytrain, Ytest]: i.index = range(i.shape[0])- 使用GridSearchCV进行参数优化
- 使用cross_val_score进行交叉验证
#实例化模型 clf = DecisionTreeClassifier(random_state=25) clf = clf.fit(Xtrain, Ytrain) score_ = clf.score(Xtest, Ytest) score_ #单词测试结果可能有影响,用交叉验证检验查看均值 score = cross_val_score(clf,X,y,cv=10).mean() score
调参
#网格搜索,计算量比较大,能够帮我们同时调整多个参数的技术
parameters = {}
#网格搜索无法将一些参数舍弃,所以可能出现分数更低的情况5. 决策树的优缺点
优点:
- 易于理解和解释,因为树木可以可视化
- 需要很少的数据准备,不需要归一化
- 使用成本低
- 能够同时处理数字和分类数据
- 能够处理多输出问题
- 是一个白盒模型,结果容易解释
- 可以使用统计测试验证模型
- 即使其假设在某种程度上违反了数据的真实模型,也能够表现良好
缺点:
- 决策树学习者可能创建过于复杂的树,导致过拟合
- 决策树可能不稳定
- 决策树的学习是基于贪婪算法,不能保证返回全局最优决策树
- 有些概念很难学习,如XOR、奇偶校验
- 如果某些类占主导地位,决策树会创建有偏的树
6. 附录
6.1 分类树参数列表
参数说明默认值criterion衡量分枝质量的指标:"gini"或"entropy""gini"splitter分枝策略:"best"或"random""best"max_depth树的最大深度Nonemin_samples_split分枝所需的最小样本数2min_samples_leaf叶子节点所需的最小样本数1min_weight_fraction_leaf叶子节点所需的最小权重比例0.0max_features分枝时考虑的最大特征数Nonerandom_state随机数种子Nonemax_leaf_nodes最大叶子节点数Nonemin_impurity_decrease分枝所需的最小不纯度减少量0.06.2 分类树属性列表
classes_: 标签的类别feature_importances_: 特征重要性max_features_: max_features参数的推断值n_classes_: 标签类别数量n_features_: 训练时使用的特征数量n_outputs_: 输出的数量tree_: 树结构的底层表示
6.3 分类树接口列表
apply(X[, check_input]): 返回每个样本的叶节点索引decision_path(X[, check_input]): 返回决策路径fit(X, y[, sample_weight, check_input]): 训练模型get_params([deep]): 获取参数predict(X[, check_input]): 预测类别predict_log_proba(X): 预测类别的对数概率predict_proba(X[, check_input]): 预测类别的概率score(X, y[, sample_weight]): 返回预测准确度set_params(**params): 设置参数
Bonus Chapter I: 实例:分类树在合成数集上的表现
通过sklearn的make_classification, make_moons, make_circles等函数生成不同类型的数据集,测试决策树在不同数据分布情况下的表现。
Bonus Chapter II: 配置开发环境&安装sklearn
开发环境配置建议:
- 新手建议:
- 直接安装Anaconda(包含所有必需的包)
- 下载地址:https://www.anaconda.com/download/
- 已有Python环境:
- 使用pip安装必要包:
bash
Copy
pip install numpy
pip install pandas
pip install scipy
pip install matplotlib
pip install -U scikit-learn- 使用conda安装:
bash
Copy
conda install numpy
conda install pandas
conda install scipy
conda install matplotlib
conda install scikit-learn注意事项:
- Anaconda的安装和pip的安装尽量不要混用
- 安装过程中的报错可以通过卸载重装解决
- Python版本要求:3.4以上
- sklearn版本要求:0.19以上