上面文章《决策树模型(一)理论》中,已详细介绍了决策树原理,包括决策树生长原理,决策树的特征选择原理,决策树剪枝策略以及决策树处理缺失值原理等等。如果您还没有阅读,可点击跳转,或关注公众号<数据STUDIO>获取文章详情。
本文将继决策树理论后,通过实际的案例应用,加深对决策树工作原理的理解。本文直接使用sklearn中决策树模型,sklearn自带的红酒数据集作为数据源。「本文字数8253」
sklearn.tree.DecisionTreeClassifier
语法
代码语言:javascript复制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)
重要参数
criterion : {"gini", "entropy"}, default="gini"
- 输入
"entropy"
,使用信息熵(Entropy) - 输入
"gini"
,使用基尼系数(Gini Impurity)
决策树找出最佳节点和最佳分枝方法,而衡量这个"最佳"的标准(criterion)叫做"不纯度"。一般地,不纯度越低,决策树对训练集的拟合越好。目前的决策树算法在分枝方法上的核心大多是围绕在对某个不纯度相关指标的最优化上。
random_state : int or RandomState, default=None
random_state
用来设置分枝中的随机模式的参数,默认None
,在高维度时随机性会表现更明显。
- 如果
int
,random_state
是随机数生成器使用的种子; - 如果输入
RandomState实例
,则random_state
为随机数生成器; - 如果
None
,随机数生成器就是通过"np.random"
使用一个RandomState
实例
splitter : {"best", "random"}, default="best"
- 输入
"best"
选择最好的分裂 - 输入
"random"
选择最好的随机分割
用于在每个节点选择分割的策略。策略是"best"
,决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_
查看)。策略是"random"
时,决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合,从而降低了过拟合。
max_depth : int, default=None
- 输入
"None"
,则展开节点直到所有的叶子都是纯净的,即不纯度为0,或者直到所有的叶子都含有少于min_samples_split
样本。 - 输入
int
,限制树的最大深度,超过设定深度的树枝全部剪掉。这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。
min_samples_split : int or float, default=2
一个节点必须要包含至少min_samples_split
个训练样本,这个节点才允许被分枝,否则 分枝就不会发生。
- 输入
int
,min_samples_split
作为最小值。 - 如果是
float
,那么min_samples_split
是一个分数和ceil(min_samples_split * n_samples)
是最小值每次分割的样本数。
min_samples_leaf : int or float, default=1
一个叶节点上所需的最小样本数。即一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf
个训练样本,否则分枝就不会发生,或分枝会朝着满足每个子节点都包含min_samples_leaf
个样本的方向去发生。
- 如果是
int
,那么考虑min_samples_leaf
作为最小值。 - 如果是
float
,那么min_samples_leaf
是一个分数和ceil(min_samples_leaf * n_samples)
是最小值每个节点的样本数。
任何深度上的分裂点,只有在每个左右分支上的训练样本超过min_samples_leaf
,才会被纳入考虑范围。这会产生平滑模型的效果,尤其是在回归树中使用。
这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本量的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,可以在回归问题中避免低方差,过拟合的叶子节点出现。对于类别不多的分类问题,等于1通常就是最佳选择。
max_features : int, float or {"auto", "sqrt", "log2"}, default=None
限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃,即是直接限制可以使用的特征数量而强行使决策树停下的参数。是用来限制高维度数据的过拟合的剪枝参数。
- 如果是
int
,那么考虑每个分割的max_features
特性。 - 如果是
float
,输入的浮点数为比例,每个分枝考虑的特征数目是int(max_features * n_features)
,输入模型的数据集的特征个数n_features
。 - 输入
"auto"
,那么max_features=sqrt(n_features)
- 输入
"sqrt"
,那么max_features=sqrt(n_features)
- 输入
"log2"
,那么max_features=log2(n_features)
- 输入
"None"
,那么max_features=n_feature
。
在不知道决策树中的各个特征的重要性的情况下,强行设定这个参数可能会导致模型学习不足。如果希望通过降维的方式防止过拟合,建议使用PCA,ICA或者特征选择模块中的降维算法。
min_impurity_decrease : float, default=0.0
限制信息增益的大小,信息增益小于设定数值的分枝不会发生。当一个节点的分枝后引起的不纯度降低大于或等于 min_impurity_decrease
中输入的数值,则这个分枝则会被保留,不会被剪枝。
带权重的不纯度下降表示为:
其中
为样本总数,
为样本总数在当前节点上,
是样本的数量
是叶子节点的样本数。
如果 "sample_weight"
在fit
接口中有值,
、
、
和
所有引用加权和,而非单纯的样本数量。
class_weight : dict, list of dict or "balanced", default=None
以{class_label: weight}
的形式与类关联的权重。如果 None
列表中字典的权重的顺序需要与各个y
在标签数据集中的排列顺序相同。
注意,对于多输出问题(包括多标签问题),定义的权重必须具体到每个标签下的每个类,其中类是字典键值对中的键。例如,对于四类多标签分类,权重应是({0: 1, 1: 1}, {0: 1, 1: 5}, {0: 1, 1: 1}, {0: 1, 1: 1})
。而不是[{1:1},{2:5},{3:1},{4:1}]
。
如果使用"balanced"
模式,将会使用y的值来自动调整与输入数据中的类频率成反比的权重,如n_samples / (n_classes * np.bincount(y))
对于多输出,将y
的每一列的权重相乘。
注意,如果指定了sample_weight
,这些权重将通过fit
接口与sample_weight
相乘。
其他参数
min_weight_fraction_leaf : float, default=0.0 一个叶节点要存在所需要的权重占输入模型的数据集的总权重的比例。 总权重由
fit
接口中的sample_weight
参数确定,当sample_weight
时None
时,默认所有样本权重相同。 max_leaf_nodes : int, default=None 最大叶子节点数量,在最佳分枝下,以max_leaf_nodes为限制来生长树。默认没有节点数量的限制。 presort : deprecated, default='deprecated' 是否预先分配数据以加快拟合中最佳分枝的发现。在大型数据集上使用默认设置决策树时,将这个参数设置为True
可能会延长训练过程,降低训练速度。当使用较小数据集或限制树的深度时,设置这个参数为True
可能会加快训练速度。
属性
classes_ : ndarray of shape (n_classes,) or list of ndarray 输出一个数组(
array
),或者一个数组的列表(list
),结构为标签的数目(n_classes
)输出所有标签。 feature_importances_ : ndarray of shape (n_features,) 输出一个数组,结构为特征的数目(n_features)。返回每个特征的重要性,一般是这个特征多次分枝中产生的信息增益的综合,亦称作"基尼重要性"(Gini importance
) max_features_ : int 输出参数max_features
的推断值 n_classes_ : int or list of int 标签类别的数据 n_features_ : int 在训练模型fit
时使用的特征个数 n_outputs_ : int 在训练模型fit
时使用的结果个数 tree_ : Tree 输出一个可以导出建好的决策树结果的端口,可以通过这个端口访问树的结构和低级属性,包括但不限于查看:
- 二叉树的结构
- 每个节点的深度以及它是否是叶子
- 使用decision_path方法的示例到达的节点
- 用apply接口取样出的叶子
- 用于预测样本的规则
- 一组样本共享的决策路径
tree_ 的更多内容参见 https://scikit-learn.org/stable/auto_examples/tree/plot_unveil_tree_structure.html#sphx-glr-download-auto-examples-tree-plot-unveil-tree-structure-py
重要接口
fit(X, y[, sample_weight, check_input, …]) 训练模型的接口,其中X代表训练样本的特征,y表示目标数据,即标签。X和y都必须是类数组结构,一般使用ndarray导入。
sample_weitht
是fit
的参数,用来为样本标签设置权重,输入的格式是一个和测试集样本量一致长度的数字数组,数组中所带的数字表示每个样本所占的权重,数组中数字的综合代表整个测试集的权重总数。 返回训练完毕的模型。 predict(X[, check_input]) 预测所提供的测试集X中样本点的标签,这里的测试集X必须和fit中提供的测试集结构一致。 返回模型预测的测试样本的标签或回归值。 predict_proba(X[, check_input]) 预测所提供的测试集X中样本点归属于各个标签的概率。 返回测试集中每个样本点所对应的每个标签的概率,各个标签按辞典顺序排列。预测的类概率是叶子节点中相同类的样本的分数。 score(X, y[, sample_weight]) 用给定测试数据和标签的平均准确度作为模型的评分标准,分数越高模型越好。其中X是测试集,y是测试集的真实标签。sample_weight是score的参数,用法与fit的参数一致。 返回给定决策树数据和标签的平均准确度,在多标签分类中,这个指标是子集精度。 apply(X[, check_input]) 输入测试集或样本点,返回每个样本点被分到的叶子节点的索引。check_input
是接口apply
的参数,输入布尔值,默认True
,通常不使用。更多参数和接口可参见 https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier
实例一 (load_wine)
导包
代码语言:javascript复制>>> import pandas as pd
>>> from sklearn import tree
>>> from sklearn .tree import DecisionTreeClassifier
>>> from sklearn.datasets import load_wine
>>> from sklearn.model_selection import train_test_split
>>> import graphviz
>>> import matplotlib.pyplot as plt
导入并探索数据集
代码语言:javascript复制>>> wine = load_wine()
>>> wine.data.shape
(178, 13)
>>> wine.target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,2, 2])
>>> wine.target_names
array(['class_0', 'class_1', 'class_2'], dtype='<U7')
>>> wine.feature_names
['alcohol',
'malic_acid',
'ash',
'alcalinity_of_ash',
'magnesium',
'total_phenols',
'flavanoids',
'nonflavanoid_phenols',
'proanthocyanins',
'color_intensity',
'hue',
'od280/od315_of_diluted_wines',
'proline']
>>> pd.concat([pd.DataFrame(wine.data, columns=wine.feature_names),pd.DataFrame(wine.target)],axis=1)
建立模型
代码语言:javascript复制# 划分训练集和测试集
>>> Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
# 建立模型
>>> clf = DecisionTreeClassifier(criterion="entropy")
>>> clf = clf.fit(Xtrain, Ytrain)
>>> score = clf.score(Xtest, Ytest) #返回预测的准确度
>>> score
0.9074074074074074
可视化决策树
代码语言:javascript复制feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜 色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
dot_data = tree.export_graphviz(clf,out_file=None
,feature_names=feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True)
graph = graphviz.Source(dot_data)
graph
#graph.render('wine')
#可保存为PDF, 但是无法显示中文
参数调节
调节随机参数
两个随机参数 random_state & splitter
clf = DecisionTreeClassifier(criterion="entropy"
,random_state=666
,splitter="random")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜 色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
dot_data = tree.export_graphviz(clf,out_file = None
,feature_names= feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True,rounded=True)
graph = graphviz.Source(dot_data)
graph
输出结果
random_state=10时的输出结果:
由此可见,不同的 random_state
或 splitter
均有不同的树结构。
剪枝参数
决策树模型是一个天生过拟合的模型,即它会在训练集上表现很好,在测试集上却表现糟糕。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。
剪枝参数有max_depth
min_samples_leaf
min_samples_split
max_features
min_impurity_decrease
可以通过学习曲线的方式选择最佳剪枝参数。
代码语言:javascript复制超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲 线,它是用来衡量不同超参数取值下模型的表现的线。
L = []
L1 = []
# 调节决策树最大深度
for i in range(2, 11):
dct = DecisionTreeClassifier(criterion='entropy'
, random_state=10
, splitter='random'
, max_depth=i
, min_samples_leaf=10
, min_samples_split=10)
dct.fit(Xtrain, Ytrain)
L.append([i, dct.score(Xtest, Ytest)])
# 调节一个节点在分枝后的每个子节点都必须包含的训练样本个数
for j in range(5,15):
dct1 = DecisionTreeClassifier(criterion='entropy'
, random_state=10
, splitter='random'
, max_depth=3
, min_samples_leaf=j
, min_samples_split=10)
dct1.fit(Xtrain, Ytrain)
L1.append([j, dct1.score(Xtest, Ytest)])
a = pd.DataFrame(L, columns = ['max_depth', '准确率'])
b = pd.DataFrame(L1, columns = ['min_samples_leaf', '准确率'])
A = [a, b]
plt.figure(figsize=(15, 5), dpi=70)
for k,v in enumerate(A):
plt.subplot(1,2,k 1)
plt.plot(v.iloc[:,0], v.准确率, color='orange')
plt.xticks(v.iloc[:,0])
plt.xlabel(v.columns[0])
plt.ylabel('准确率')
plt.title(f'{v.columns[0]}的学习曲线');
输出结果
由学习曲线可见,当max_depth=3
时准确率最高,而min_samples_leaf=13
时准确率最高。再来看看当max_depth=3
和 min_samples_leaf=13
时的决策树结构。
其余剪枝参数的调节同样可以使用学习曲线。可以先从max_depth
开始调节,确定最佳参数后,再去调节其余参数,直至模型达到一个最佳状态停止。这样每次确定一个最佳参数是一种局部最优思想。一般而言,使用局部最优达到全局最优即能满足一般情况。如果更加严格的要求,可使用网格搜索选取最佳参数,但由于网格一样全局搜索最佳参数,计算量极大,较耗时。在求最佳参数而不关注训练时间的情况下,可选用网格搜索选取最佳参数。
目标权重参数
完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。比如说,在银行要 判断"一个办了信用卡的人是否会违约",即是vs否(1%:99%
)的比例。这种分类状况下,即便模型什么也不 做,全把结果预测成"否",正确率也能有99%
。因此我们要使用class_weight
参数对样本标签进行一定的均衡,给 少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None
,此模式表示自动给 与数据集中的所有标签相同的权重。
有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_ weight_fraction_leaf
这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_ fraction_leaf
)将比不知道样本权重的标准(比如min_samples_leaf
)更少偏向主导类。如果样本是加权的,则使 用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。
实例二 (load_iris)
本案例主要展示下决策树分类边界
代码
代码语言:javascript复制import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
# 设置好参数
n_classes = 3
plot_colors = "ryb"
plot_step = 0.02
# 导入数据集合
iris = load_iris()
plt.figure(figsize=(15,10))
for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3],
[1, 2], [1, 3], [2, 3]]):
# 选取二维数据进行两两比较
X = iris.data[:, pair]
y = iris.target
# 建立并训练模型
clf = DecisionTreeClassifier().fit(X, y)
# 画出决策边界
plt.subplot(2, 3, pairidx 1)
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step),
np.arange(y_min, y_max, plot_step))
plt.tight_layout(h_pad=0.5, w_pad=0.5, pad=2.5)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlBu)
plt.xlabel(iris.feature_names[pair[0]], fontsize= 20)
plt.ylabel(iris.feature_names[pair[1]], fontsize= 20)
# Plot the training points
for i, color in zip(range(n_classes), plot_colors):
idx = np.where(y == i)
plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i],
cmap=plt.cm.RdYlBu, edgecolor='black', s=25)
plt.suptitle("Decision surface of a decision tree using paired features", y=1.02, fontsize= 25)
plt.legend(loc='lower right', borderpad=0, handletextpad=0, fontsize= 15)
plt.axis("tight")
输出结果
sklearn.tree.DecisionTreeRegressor
语法
代码语言:javascript复制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
这样的参数。
回归树中,最重要的不同即是归树衡量分枝质量的指标。
criterion : {"mse", "friedman_mse", "mae"}, default="mse"
- 输入
"mse"
使用均方误差mean squared error(MSE)
,父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2
损失。 - 输入
"friedman_mse"
使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差。 - 输入
"mae"
使用绝对平均误差MAE(mean absolute error)
,这种指标使用叶节点的中值来最小化L1
损失。
回归树中,MSE
不只是我们的分枝质量衡量指标,也是我们最常用的衡量回归树回归质量的指标。
值得一提的是,虽然均方误差永远为正,但是sklearn当中使用均方误差作为评判标准时,却是计算”负均方误差"neg_mean_squared_error"
。这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均方误差本身是一种误差,所以被sklearn
划分为模型的一种损失(loss
),因此在sklearn
当中,都以负数表示。真正的均方误差MSE
的数值,其实就是"neg_mean_squared_error"
去掉负号的数字
回归树决策图像
在二维平面上来观察决策树是怎样拟合一条曲线的。回归树来拟合正弦曲线,并添加一些噪声来观察回归树的表现。
模型建立
代码语言:javascript复制import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
rng = np.random.RandomState(66)
X = np.sort(5 * rng.rand(80,1), axis=0)
y = np.sin(X).ravel()
y[::5] = 3 * (0.5 - rng.rand(16))
#np.random.rand(数组结构),生成随机数组的函数
#了解降维函数ravel()的用法
np.random.random((2,1))
np.random.random((2,1)).ravel()
np.random.random((2,1)).ravel().shape
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)
可视化
代码语言:javascript复制plt.figure(figsize=(10,6))
plt.scatter(X, y, s=25, edgecolor="blue",c="yellowgreen", label="data")
plt.plot(X_test, y_1, color="black",label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="orange", label="max_depth=5", linewidth=2)
plt.xlabel("data",fontsize=15)
plt.ylabel("target",fontsize=15)
plt.title("Decision Tree Regression",fontsize=20)
plt.legend()
plt.show()
输出结果
可见,回归树学习了近似正弦曲线的局部线性回归。
且如果树的最大深度(max_depth=5
) 设置得太高,则决策树学习得太精细,它从训练数据中学了很多细节,包括噪声的学习,从而使模型偏离真实的正弦曲线,形成过拟合。当最大深度(max_depth=3
) 设置值降低时,其过拟合现像显著降低。由此可见,参数最大深度(max_depth
) 可有效控制树模型的复杂程度。
实例三(泰坦尼克号幸存者的预测)
泰坦尼克号的沉没是世界上最严重的海难事故之一,今天我们通过分类树模型来预测一下哪些人可能成为幸存者。数据集来自https://www.kaggle.com/c/titanic,数据集包含两个csv格式文件,data使用的数据,test为kaggle提供的测试集。
导入本次实例子所需要的python包
代码语言:javascript复制import pandas as pd
import numpy as np
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
读取数据
读者可联系笔者免费获取数据集。
代码语言:javascript复制data = pd.read_csv('./data.csv')
data.head()
数据处理
代码语言:javascript复制#删除缺失值过多的列,和观察判断来说和预测的y没有关系的列
data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1)
#处理缺失值,对缺失值较多的列进行填补,有一些特征只确实一两个值,可以采取直接删除记录的方法
data["Age"] = data["Age"].fillna(data["Age"].mean())
data = data.dropna()
# 将分类变量转换为数值型变量
# 将二分类变量转换为数值型变量
# astype能够将一个pandas对象转换为某种类型,和apply(int(x))不同,astype可以将文本类转换为数字,
# 用这个方式可以很便捷地将二分类特征转换为0~1
data["Sex"] = (data["Sex"] == "male").astype("int")
#将三分类变量转换为数值型变量
labels = data["Embarked"].unique().tolist()
data["Embarked"] = data["Embarked"].apply(lambda x: labels.index(x))
#查看处理后的数据集
data.head()
划分训练集和测试集
代码语言:javascript复制X = data.iloc[:,data.columns != "Survived"]
y = data.iloc[:,data.columns == "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])
模型建立与训练
代码语言:javascript复制clf = DecisionTreeClassifier(random_state=25)
clf = clf.fit(Xtrain, Ytrain)
score_ = clf.score(Xtest, Ytest)
score_
0.7453183520599251
代码语言:javascript复制score = cross_val_score(clf,X,y,cv=10).mean()
score
0.7469611848825333
模型初步调参
调节参数 max_depth
,并查看模型拟合情况
trian_list = []
test_list = []
for i in range(10):
clf = DecisionTreeClassifier(random_state=25
,max_depth=i 1
,criterion="entropy"
)
clf = clf.fit(Xtrain, Ytrain)
score_trian = clf.score(Xtrain,Ytrain)
score_test = cross_val_score(clf,X,y,cv=10).mean()
trian.append(score_tr)
test.append(score_te)
print(max(te))
plt.figure(figsize=(10, 6))
plt.plot(range(1,11),trian_list,color="orange",label="train")
plt.plot(range(1,11),test_list,color="black",label="test")
plt.xticks(range(1,11))
plt.legend()
plt.show()
# 这里为什么使用“entropy”?因为我们注意到,在最大深度=3的时候,模型拟合不足,
# 在训练集和测试集上的表现接近,但却都不是非常理想,只能够达到74%左右,所以我们要使用entropy。
输出结果
0.8166624106230849
网格搜索调节参数
代码语言:javascript复制gini_thresholds = np.linspace(0,0.5,20)
parameters = {'splitter':('best','random')
,'criterion':("gini","entropy")
,"max_depth":[*range(1,10)]
,'min_samples_leaf':[*range(1,50,5)]
,'min_impurity_decrease':[*np.linspace(0,0.5,20)]
}
clf = DecisionTreeClassifier(random_state=25)
GS = GridSearchCV(clf, parameters, cv=10)
GS.fit(Xtrain,Ytrain)
获取最佳参数
代码语言:javascript复制>>> GS.best_params_
{'criterion': 'gini',
'max_depth': 8,
'min_impurity_decrease': 0.0,
'min_samples_leaf': 6,
'splitter': 'best'}
>>> GS.best_score_
0.8327188940092165
推荐阅读