本课程是中国大学慕课《机器学习》的“决策树”章节的课后代码。

课程地址:

https://www.icourse163.org/course/WZU-1464096179

课程完整代码:

https://github.com/fengdu78/WZU-machine-learning-course

代码修改并注释:黄海广,haiguang2000@wzu.edu.cn

机器学习练习7 决策树

代码修改并注释:黄海广,haiguang2000@wzu.edu.cn

1.分类决策树模型是表示基于特征对实例进行分类的树形结构。决策树可以转换成一个if-then规则的集合,也可以看作是定义在特征空间划分上的类的条件概率分布。

2.决策树学习旨在构建一个与训练数据拟合很好,并且复杂度小的决策树。因为从可能的决策树中直接选取最优决策树是NP完全问题。现实中采用启发式方法学习次优的决策树。

决策树学习算法包括3部分:特征选择、树的生成和树的剪枝。常用的算法有ID3、 C4.5和CART。

3.特征选择的目的在于选取对训练数据能够分类的特征。特征选择的关键是其准则。常用的准则如下:

(1)样本集合对特征的信息增益(ID3)

其中,是数据集的熵,是数据集的熵,是数据集对特征的条件熵。是中特征取第个值的样本子集,是中属于第类的样本子集。是特征取 值的个数,是类的个数。

(2)样本集合对特征的信息增益比(C4.5)

其中,是信息增益,是数据集的熵。

(3)样本集合的基尼指数(CART)

特征条件下集合的基尼指数:

4.决策树的生成。通常使用信息增益最大、信息增益比最大或基尼指数最小作为特征选择的准则。决策树的生成往往通过计算信息增益或其他指标,从根结点开始,递归地产生决策树。这相当于用信息增益或其他准则不断地选取局部最优的特征,或将训练集分割为能够基本正确分类的子集。

5.决策树的剪枝。由于生成的决策树存在过拟合问题,需要对它进行剪枝,以简化学到的决策树。决策树的剪枝,往往从已生成的树上剪掉一些叶结点或叶结点以上的子树,并将其父结点或根结点作为新的叶结点,从而简化生成的决策树。

import numpy as np
import pandas as pd
import math
from math import log

创建数据

def create_data():datasets = [['青年', '否', '否', '一般', '否'],['青年', '否', '否', '好', '否'],['青年', '是', '否', '好', '是'],['青年', '是', '是', '一般', '是'],['青年', '否', '否', '一般', '否'],['中年', '否', '否', '一般', '否'],['中年', '否', '否', '好', '否'],['中年', '是', '是', '好', '是'],['中年', '否', '是', '非常好', '是'],['中年', '否', '是', '非常好', '是'],['老年', '否', '是', '非常好', '是'],['老年', '否', '是', '好', '是'],['老年', '是', '否', '好', '是'],['老年', '是', '否', '非常好', '是'],['老年', '否', '否', '一般', '否'],]labels = [u'年龄', u'有工作', u'有自己的房子', u'信贷情况', u'类别']# 返回数据集和每个维度的名称return datasets, labels
datasets, labels = create_data()
train_data = pd.DataFrame(datasets, columns=labels)
train_data
年龄 有工作 有自己的房子 信贷情况 类别
0 青年 一般
1 青年
2 青年
3 青年 一般
4 青年 一般
5 中年 一般
6 中年
7 中年
8 中年 非常好
9 中年 非常好
10 老年 非常好
11 老年
12 老年
13 老年 非常好
14 老年 一般

def calc_ent(datasets):data_length = len(datasets)label_count = {}for i in range(data_length):label = datasets[i][-1]if label not in label_count:label_count[label] = 0label_count[label] += 1ent = -sum([(p / data_length) * log(p / data_length, 2)for p in label_count.values()])return ent

条件熵

def cond_ent(datasets, axis=0):data_length = len(datasets)feature_sets = {}for i in range(data_length):feature = datasets[i][axis]if feature not in feature_sets:feature_sets[feature] = []feature_sets[feature].append(datasets[i])cond_ent = sum([(len(p) / data_length) * calc_ent(p)for p in feature_sets.values()])return cond_ent
calc_ent(datasets)
0.9709505944546686

信息增益

def info_gain(ent, cond_ent):return ent - cond_ent
def info_gain_train(datasets):count = len(datasets[0]) - 1ent = calc_ent(datasets)best_feature = []for c in range(count):c_info_gain = info_gain(ent, cond_ent(datasets, axis=c))best_feature.append((c, c_info_gain))print('特征({}) 的信息增益为: {:.3f}'.format(labels[c], c_info_gain))# 比较大小best_ = max(best_feature, key=lambda x: x[-1])return '特征({})的信息增益最大,选择为根节点特征'.format(labels[best_[0]])
info_gain_train(np.array(datasets))
特征(年龄) 的信息增益为:0.083
特征(有工作) 的信息增益为:0.324
特征(有自己的房子) 的信息增益为:0.420
特征(信贷情况) 的信息增益为:0.363'特征(有自己的房子)的信息增益最大,选择为根节点特征'

利用ID3算法生成决策树

# 定义节点类 二叉树
class Node:def __init__(self, root=True, label=None, feature_name=None, feature=None):self.root = rootself.label = labelself.feature_name = feature_nameself.feature = featureself.tree = {}self.result = {'label:': self.label,'feature': self.feature,'tree': self.tree}def __repr__(self):return '{}'.format(self.result)def add_node(self, val, node):self.tree[val] = nodedef predict(self, features):if self.root is True:return self.labelreturn self.tree[features[self.feature]].predict(features)class DTree:def __init__(self, epsilon=0.1):self.epsilon = epsilonself._tree = {}# 熵@staticmethoddef calc_ent(datasets):data_length = len(datasets)label_count = {}for i in range(data_length):label = datasets[i][-1]if label not in label_count:label_count[label] = 0label_count[label] += 1ent = -sum([(p / data_length) * log(p / data_length, 2)for p in label_count.values()])return ent# 经验条件熵def cond_ent(self, datasets, axis=0):data_length = len(datasets)feature_sets = {}for i in range(data_length):feature = datasets[i][axis]if feature not in feature_sets:feature_sets[feature] = []feature_sets[feature].append(datasets[i])cond_ent = sum([(len(p) / data_length) * self.calc_ent(p)for p in feature_sets.values()])return cond_ent# 信息增益@staticmethoddef info_gain(ent, cond_ent):return ent - cond_entdef info_gain_train(self, datasets):count = len(datasets[0]) - 1ent = self.calc_ent(datasets)best_feature = []for c in range(count):c_info_gain = self.info_gain(ent, self.cond_ent(datasets, axis=c))best_feature.append((c, c_info_gain))# 比较大小best_ = max(best_feature, key=lambda x: x[-1])return best_def train(self, train_data):"""input:数据集D(DataFrame格式),特征集A,阈值etaoutput:决策树T"""_, y_train, features = train_data.iloc[:, :-1], train_data.iloc[:,-1], train_data.columns[:-1]# 1,若D中实例属于同一类Ck,则T为单节点树,并将类Ck作为结点的类标记,返回Tif len(y_train.value_counts()) == 1:return Node(root=True, label=y_train.iloc[0])# 2, 若A为空,则T为单节点树,将D中实例树最大的类Ck作为该节点的类标记,返回Tif len(features) == 0:return Node(root=True,label=y_train.value_counts().sort_values(ascending=False).index[0])# 3,计算最大信息增益 同5.1,Ag为信息增益最大的特征max_feature, max_info_gain = self.info_gain_train(np.array(train_data))max_feature_name = features[max_feature]# 4,Ag的信息增益小于阈值eta,则置T为单节点树,并将D中是实例数最大的类Ck作为该节点的类标记,返回Tif max_info_gain < self.epsilon:return Node(root=True,label=y_train.value_counts().sort_values(ascending=False).index[0])# 5,构建Ag子集node_tree = Node(root=False, feature_name=max_feature_name, feature=max_feature)feature_list = train_data[max_feature_name].value_counts().indexfor f in feature_list:sub_train_df = train_data.loc[train_data[max_feature_name] ==f].drop([max_feature_name], axis=1)# 6, 递归生成树sub_tree = self.train(sub_train_df)node_tree.add_node(f, sub_tree)# pprint.pprint(node_tree.tree)return node_treedef fit(self, train_data):self._tree = self.train(train_data)return self._treedef predict(self, X_test):return self._tree.predict(X_test)
datasets, labels = create_data()
data_df = pd.DataFrame(datasets, columns=labels)
dt = DTree()
tree = dt.fit(data_df)
tree
{'label:': None, 'feature': 2, 'tree': {'否': {'label:': None, 'feature': 1, 'tree': {'否': {'label:': '否', 'feature': None, 'tree': {}}, '是': {'label:': '是', 'feature': None, 'tree': {}}}}, '是': {'label:': '是', 'feature': None, 'tree': {}}}}
dt.predict(['老年', '否', '否', '一般'])
'否'

Scikit-learn实例

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter

使用Iris数据集,我们可以构建如下树:

# data
def create_data():iris = load_iris()df = pd.DataFrame(iris.data, columns=iris.feature_names)df['label'] = iris.targetdf.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']data = np.array(df.iloc[:100, [0, 1, -1]])# print(data)return data[:, :2], data[:, -1],iris.feature_names[0:2]X, y,feature_name= create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

决策树分类

from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import graphviz
from sklearn import treeclf = DecisionTreeClassifier()
clf.fit(X_train, y_train,)clf.score(X_test, y_test)
0.9666666666666667

一旦经过训练,就可以用 plot_tree函数绘制树:

tree.plot_tree(clf)
[Text(197.83636363636364, 195.696, 'X[0] <= 5.45\ngini = 0.5\nsamples = 70\nvalue = [36, 34]'),Text(121.74545454545455, 152.208, 'X[1] <= 2.8\ngini = 0.157\nsamples = 35\nvalue = [32, 3]'),Text(60.872727272727275, 108.72, 'X[0] <= 4.75\ngini = 0.444\nsamples = 3\nvalue = [1, 2]'),Text(30.436363636363637, 65.232, 'gini = 0.0\nsamples = 1\nvalue = [1, 0]'),Text(91.30909090909091, 65.232, 'gini = 0.0\nsamples = 2\nvalue = [0, 2]'),Text(182.61818181818182, 108.72, 'X[0] <= 5.3\ngini = 0.061\nsamples = 32\nvalue = [31, 1]'),Text(152.1818181818182, 65.232, 'gini = 0.0\nsamples = 29\nvalue = [29, 0]'),Text(213.05454545454546, 65.232, 'X[1] <= 3.2\ngini = 0.444\nsamples = 3\nvalue = [2, 1]'),Text(182.61818181818182, 21.744, 'gini = 0.0\nsamples = 1\nvalue = [0, 1]'),Text(243.4909090909091, 21.744, 'gini = 0.0\nsamples = 2\nvalue = [2, 0]'),Text(273.92727272727274, 152.208, 'X[1] <= 3.5\ngini = 0.202\nsamples = 35\nvalue = [4, 31]'),Text(243.4909090909091, 108.72, 'gini = 0.0\nsamples = 31\nvalue = [0, 31]'),Text(304.3636363636364, 108.72, 'gini = 0.0\nsamples = 4\nvalue = [4, 0]')]

也可以导出树

tree_pic = export_graphviz(clf, out_file="mytree.pdf")
with open('mytree.pdf') as f:dot_graph = f.read()
graphviz.Source(dot_graph)

或者,还可以使用函数 export_text以文本格式导出树。此方法不需要安装外部库,而且更紧凑:

from sklearn.tree import export_text
r = export_text(clf,feature_name)
print(r)
|--- sepal width (cm) <= 3.15
|   |--- sepal length (cm) <= 4.95
|   |   |--- sepal width (cm) <= 2.65
|   |   |   |--- class: 1.0
|   |   |--- sepal width (cm) >  2.65
|   |   |   |--- class: 0.0
|   |--- sepal length (cm) >  4.95
|   |   |--- class: 1.0
|--- sepal width (cm) >  3.15
|   |--- sepal length (cm) <= 5.85
|   |   |--- class: 0.0
|   |--- sepal length (cm) >  5.85
|   |   |--- class: 1.0

决策树回归

import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# Create a random dataset
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))
# Fit regression model
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)# Predict
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)# Plot the results
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black", c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()

决策树调参

# 导入库
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeRegressor
from sklearn import metrics
# 导入数据集
X = datasets.load_iris()  # 以全部字典形式返回,有data,target,target_names三个键
data = X.data
target = X.target
name = X.target_names
x, y = datasets.load_iris(return_X_y=True)  # 能一次性取前2个
print(x.shape, y.shape)
(150, 4) (150,)
# 数据分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.2,random_state=100)
# 用GridSearchCV寻找最优参数(字典)
param = {'criterion': ['gini'],'max_depth': [30, 50, 60, 100],'min_samples_leaf': [2, 3, 5, 10],'min_impurity_decrease': [0.1, 0.2, 0.5]
}
grid = GridSearchCV(DecisionTreeClassifier(), param_grid=param, cv=6)
grid.fit(x_train, y_train)
print('最优分类器:', grid.best_params_, '最优分数:', grid.best_score_)  # 得到最优的参数和分值
最优分类器: {'criterion': 'gini', 'max_depth': 30, 'min_impurity_decrease': 0.2, 'min_samples_leaf': 3} 最优分数: 0.9416666666666665

参考

  • https://github.com/fengdu78/lihang-code

  • 《统计学习方法》,清华大学出版社,李航著,2019年出版

  • https://scikit-learn.org

【机器学习】决策树代码练习相关推荐

  1. 机器学习决策树DecisionTree以及python代码实现

    机器学习决策树DecisionTree以及python代码实现 1.基本算法原理 2.选择最优特征进行划分 2.1信息增益 2.2信息增益率 2.3基尼系数 4.连续值以及缺失值的处理 4.1连续值的 ...

  2. 机器学习——决策树学习

    机器学习--决策树学习 一.什么是决策树 二.决策树的学习过程 特征选择: 决策树生成: 剪枝: 三.决策树的一个具体的实例 导入数据 python strip() 函数和 split() 函数的详解 ...

  3. 3.1 机器学习 --- 决策树

    3.1 机器学习 - 决策树 一 金融评分卡 模型做好后尽量快的上线,以符合要求的模型,尽快上线. 超参数赋予权重,使得模型的参数不一致,而达到均衡样本数据 二 决策树原理 1. 找女朋友 性别:男 ...

  4. 关于《机器学习决策树导出图片、PDF支持中文》解决办法

    很久没有更新博客了,一直以为自己默默无闻,埋头苦干.实际上是一种懒惰! 2020年的春天,是一段难忘的记忆!在这段特殊的时光里,让我静心思考,潜心研究.每每遇到技术困惑,总能在CSDN找到解决办法,由 ...

  5. 机器学习实用代码汇总(你想要的这里都有)

    机器学习实用代码汇总(你想要的这里都有) 文章目录 机器学习实用代码汇总(你想要的这里都有) 前言 一.数据导入 1.数据文件读取 2.提取特征和标签 3.数据分布及关系图(ProfileReport ...

  6. 机器学习 --- 决策树(educode实训作业)

    引言:本文主要对educoder机器学习 --- 决策树的实训作业进行讲解,创造不易!请您点点关注,点点收藏叭!!! 目录 第1关:什么是决策树 任务描述 相关知识 引例 决策树的相关概念 编程要求 ...

  7. 机器学习 决策树篇——解决离散变量的分类问题

    机器学习 决策树篇--解决离散变量的分类问题 摘要 熵增益和熵增益率计算 熵增益和熵增益率运行结果 离散变量的决策树模型 决策树模型运行结果 摘要 本文通过python实现了熵增益和熵增益率的计算.实 ...

  8. 机器学习——决策树剪枝

    目录 一.决策树剪枝策略 1.1剪枝目的 1.2剪枝策略 1.3判断决策树泛化性能是否提升的方法 二.预剪枝 (prepruning) 2.1概述 2.2预剪枝优缺点 2.3代码实现 三.后剪枝(po ...

  9. 机器学习——决策树模型:Python实现

    机器学习--决策树模型:Python实现 1 决策树模型的代码实现 1.1 分类决策树模型(DecisionTreeClassifier) 1.2 回归决策树模型(DecisionTreeRegres ...

最新文章

  1. javascript全栈开发实践-准备
  2. 【一周论文速递】自然语言处理最新论文!
  3. java_oop_接口
  4. 你知道数据中心宕机的真正成本吗?
  5. Yii2.0 limit(1)与one()
  6. 维密求变,“自救”还是“挖坟”?
  7. Flutter 制作漂亮的登录表单
  8. 【.NET Core项目实战-统一认证平台】第五章 网关篇-自定义缓存Redis
  9. oracle 10.2.0.1升级到10.2.0.4
  10. Intel Sandy Bridge/Ivy Bridge架构/微架构/流水线 (4) - 流水线前端概述
  11. 串口如何接收数据_原创分享 | S71200通过串口服务器读取MODBUS RTU设备
  12. es的doc_value对排序字段的作用
  13. Unity3D界面功能操作讲解【转http://www.cnblogs.com/fortomorrow/archive/2012/10/28/unity01.html】...
  14. 【JSP】错误页面处理
  15. 惠普win7驱动_win7怎么样打开无线网卡开关
  16. 密码学复习笔记2【分组密码/S-DES、DES】
  17. 推荐系统实践(三)ICF和UCF
  18. Linux:安装Debian最新10.x操作系统(超详细)
  19. gammaray报Error: gdb: Yama security extension is blocking runtime attaching, see /proc/sys/kernel/yam
  20. R语言survival包clogit函数构建条件logistic回归模型、summary函数查看模型汇总统计信息、通过似然比检验分析结果判断模型有无统计学意义

热门文章

  1. IOS NSArray 倒序
  2. chapter16 计算机体系结构基础
  3. Oracle Rman 命令详解(List report backup configure)
  4. Web 标准实践系列(一)——Google 的首页
  5. UVA1629 Cake slicing
  6. Luogu P1091 合唱队形
  7. Linker Scripts3--简单的链接脚本命令2-Assigning Values to Symbols
  8. Java VisualVM插件地址
  9. 动态嵌套游标解决方案
  10. JavaScript中的各种宽高以及位置总结