决策树
决策树
决策树是一种基本的分类与回归方法,是最经常使用的数据挖掘算法之一。
决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-else 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。
决策树学习通常包括 3 个步骤:特征选择、决策树的生成和决策树的修剪。
决策树学习的损失函数通常是正则化的极大似然函数,决策树学习属于监督学习,可以认为是学习一个分类规则。
from sklearn.datasets import load_iris
from sklearn import tree
import numpy as np
iris = load_iris()
clf = tree.DecisionTreeClassifier(min_samples_leaf=15)
clf = clf.fit(iris.data, iris.target)
# 决策树模型为:先左后右,先上后下 负数表示没有
print("树结构-左节点:"+str(clf.tree_.children_left))
print("树结构-右节点:"+str(clf.tree_.children_right))
print("节点分裂特征:"+str(clf.tree_.feature))
print("节点分裂阈值:"+str(np.round(clf.tree_.threshold,2)))
print("节点类别:"+str(clf.classes_.take( [ np.argmax(i) for i in clf.tree_.value])))
索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
左节点 | 1 | -1 | 3 | 4 | -1 | -1 | 7 | -1 | -1 |
右节点 | 2 | -1 | 6 | 5 | -1 | -1 | 8 | -1 | -1 |
分类特征 | 2 | -2 | 3 | 2 | -2 | -2 | 0 | -2 | -2 |
分裂阈值 | 2.45 | -2 | 1.75 | 4.45 | -2 | -2 | 6.35 | -2 | -2 |
节点类别 | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 2 | 2 |
那么,给定一组样本数据,决策树如何确定第一个条件呢?
决策树的基尼不纯度(Gini impurity)是衡量一个数据集的不纯度或不一致性的一种指标。基尼不纯度越小,数据越纯。如果所有样本属于同一个类别,基尼不纯度为0。
假设有10个水果,其中4个香蕉、3个苹果、3个梨子,则基尼不纯度为:
简单示例
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
clf = DecisionTreeClassifier(random_state=0)
# 计算最小成本复杂性修剪期间的修剪路径
path = clf.cost_complexity_pruning_path(X_train, y_train)
# 从路径中提取alpha值和相应的决策树
# 剪枝期间子树的有效 alpha
# 代价复杂度剪枝法,实质就是在树的复杂度与准确性之间取得一个平衡点。
# 原理参考:https://blog.csdn.net/ywj_1991/article/details/126846155
ccp_alphas, impurities = path.ccp_alphas, path.impurities
# 在 DecisionTreeClassifier中, 这种剪枝技术是通过成本复杂度参数ccp_alpha来参数化的。更大的ccp_alpha值增加被剪枝的节点数。
clfs = []
# ccp_alphas的值是通过cost_complexity_pruning_path获得的
for ccp_alpha in ccp_alphas:
# 每个循环创建一个决策树并将其添加到列表中
clf = DecisionTreeClassifier(random_state=0, ccp_alpha=ccp_alpha)
# 拟合决策树
clf.fit(X_train, y_train)
# 决策树模型为:先左后右,先上后下 负数表示没有
print("{} | 树结构-左节点长度:{},树结构-右节点长度:{}".format(ccp_alpha,len(clf.tree_.children_right),len(clf.tree_.children_left)))
# 将决策树添加到列表中
clfs.append(clf)
print("Number of nodes in the last tree is: {} with ccp_alpha: {}".format(
clfs[-1].tree_.node_count, ccp_alphas[-1]))
# 删除 ccp_alphas的最后一个值, 因为它对应于完全未剪枝的树
clfs = clfs[:-1]
# ccp_alphas也需要删除最后一个值, 因为它是完全未剪枝的树对应的值
ccp_alphas = ccp_alphas[:-1]
效果评估
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
clf = DecisionTreeClassifier(random_state=0)
# 计算最小成本复杂 性修剪期间的修剪路径
path = clf.cost_complexity_pruning_path(X_train, y_train)
# 从路径中提取alpha值和相应的决策树
# 剪枝期间子树的有效 alpha
# 代价复杂度剪枝法,实质就是在树的复杂度与准确性之间取得一个平衡点。
# 原理参考:https://blog.csdn.net/ywj_1991/article/details/126846155
ccp_alphas, impurities = path.ccp_alphas, path.impurities
# 在 DecisionTreeClassifier中, 这种剪枝技术是通过成本复杂度参数ccp_alpha来参数化的。更大的ccp_alpha值增加被剪枝的节点数。
clfs = []
# ccp_alphas的值是通过cost_complexity_pruning_path获得的
for ccp_alpha in ccp_alphas:
# 每个循环创建一个决策树并将其添加到列表中
clf = DecisionTreeClassifier(random_state=0, ccp_alpha=ccp_alpha)
# 拟合决策树
clf.fit(X_train, y_train)
# 决策树模型为:先左后右,先上后下 负数表示没有
print("{} | 树结构-左节点长度:{},树结构-右节点长度:{}".format(ccp_alpha,len(clf.tree_.children_right),len(clf.tree_.children_left)))
# 将决策树添加到列表中
clfs.append(clf)
print("Number of nodes in the last tree is: {} with ccp_alpha: {}".format(
clfs[-1].tree_.node_count, ccp_alphas[-1]))
# 删除 ccp_alphas的最后一个值, 因为它对应于完全未剪枝的树
clfs = clfs[:-1]
# ccp_alphas也需要删除最后一个值, 因为它是完全未剪枝的树对应的值
ccp_alphas = ccp_alphas[:-1]
# 绘制每个alpha值的树的测试集精度和训练集精度
node_counts = [clf.tree_.node_count for clf in clfs]
# 计算每个树的测试集精度和训练集精度
depth = [clf.tree_.max_depth for clf in clfs]
# 绘制精度与alpha的关系
train_scores = [clf.score(X_train, y_train) for clf in clfs]
# 绘制测试集精度
test_scores = [clf.score(X_test, y_test) for clf in clfs]
fig, ax = plt.subplots()
ax.plot(ccp_alphas, train_scores, marker='o', label="train",
drawstyle="steps-post")
ax.plot(ccp_alphas, test_scores, marker='o', label="test",
drawstyle="steps-post")
ax.legend()
plt.show()
'''
当 ccp_alpha 设置为0, 并保留DecisionTreeClassifier的其他默认参数时, 树就过拟合了,
使训练的准确率达到100%,测试的准确率达到88%。
随着alpha的增加,更多的树被剪枝,从而创建了一个泛化更好的决策树。
在本例中,设置 ccp_alpha=0.015可以最大限度地提高测试的准确率。
'''
模型保存
import pickle
import os
# 保存模型
with open('clf_model_v1.pickle','wb') as f:
pickle.dump(clf,f)
# 加载模型
with open('clf_model_v1.pickle','rb') as f:
clf2 = pickle.load(f)
# 删除模型
os.remove('clf_model_v1.pickle')
import joblib
# 保存模型
joblib.dump(clf, 'new_app_model_v1.pkl')
# 加载模型
clf3 = joblib.load('new_app_model_v1.pkl')
# 删除模型
os.remove('new_app_model_v1.pkl')