【机器学习sklearn】决策树(Decision Tree)算法

提示:这里是一只努力肯📕的小白 有错就改 非礼勿喷:)


前言

天可补,海可填,南山可移,日月既往,不可复追。

决策树(Decision Tree)是基于树结构来进行决策的。(分类、回归)
一棵决策树包含一个根结点、若干个内部节点和若干个叶结点。
最终目的是将样本越分越纯。
“伯乐相马” 好典故!!!(摘自决策树分类算法(if-else原理)
决策树流程图


tips: 路漫漫其修远兮 吾将上下而求索

一、决策树学习基本算法

决策树学习的目的是为了产生一棵泛化能力强,即处理未见示例能力强的决策树,遵循“分而治之”(divide-and-conquer)策略。其生成是一个递归的过程。下图为机器学习中的决策树学习基本算法流程(请认真体会~)。
决策树学习算法

1.信息熵(Information Entropy)

决策树学习的关键是如何选择最优划分属性。划分过程中,决策树的分支结点所包含的样本尽可能属于同一类别,结点的“纯度”(purity)越来越高。

信息熵是度量样本集合纯度最常用的一种指标。
假定当前样本集合 D D D中第 k k k类样本所占的比例来为 p k   ( k = 1 , 2 , . . . , ∣ y ∣ ) p_k \ (k=1,2,...,|y|) pk (k=1,2,...,y),则 D D D信息熵定义为
E n t ( D ) = − ∑ k = 1 ∣ y ∣ p k   l o g 2   p k Ent(D)=-\sum_{k=1}^{|y|}p_k \ log_2\ p_k Ent(D)=k=1ypk log2 pk
E n t ( D ) Ent(D) Ent(D)的值越小,则 D D D的纯度越高。

2.信息增益(Information gain)- ID3决策树

假定离散属性 a a a V V V个可能的取值 { a 1 , a 2 , . . . , a V } \lbrace a^1,a^2,...,a^V \rbrace {a1,a2,...,aV},若使用 a a a来对样本集 D D D进行划分,则会产生 V V V个分支结点,其中第 v v v个分支结点包含了 D D D中所有在属性 a a a上取值为 a v a^v av的样本,即为 D v D^v Dv

给分支结点赋予权重 ∣ D v ∣ ∣ D ∣ \frac{|D^v|} {|D|} DDv,样本数越多的分支结点的影响越大,信息增益越大,使用属性a对样本集 D D D进行划分所获得的纯度提升越大。
G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) Gain(D,a)=Ent(D)-\sum_{v=1}^{V} \frac {|D^v|} {|D|}Ent(D^v) Gain(D,a)=Ent(D)v=1VDDvEnt(Dv)

ID3(Iterative Dichotomiser,迭代二分器)决策树学习算法,以信息增益准则来选择划分属性。
信息增益准则对可取值数目较多的属性有所偏好。
从属性集A中选择最优划分属性 a ∗ = a r g   m a x   a ∈ A G a i n ( D , a ) a_*=\underset{a \in A}{arg\ max\ } Gain(D,a) a=aAarg max Gain(D,a)

3.增益率(Gain Ratio)- C4.5决策树

C4.5决策树算法不直接使用信息增益,而是使用增益率来选择最优划分属性。
增益率准则对可取值数目较少的属性有所偏好。
G a i n _ r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) Gain\_ratio(D,a)= \frac {Gain(D,a)} {IV(a)} Gain_ratio(D,a)=IV(a)Gain(D,a)
其中, I V ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ l o g 2 ∣ D v ∣ ∣ D ∣ IV(a)=-\sum_{v=1}^{V} \frac {|D^v|} {|D|}log_2 \frac {|D^v|} {|D|} IV(a)=v=1VDDvlog2DDv
称为属性a的固有值(Intrinsic Value)。属性a的可能取值数目越多,则 I V ( a ) IV(a) IV(a)的值通常会越大。

C4.5决策树并未完全使用“增益率”代替“信息增益”,而是采用一种启发式的方法: 先选出信息增益高于平均水平的属性,然后再从中选择增益率最高的。

4.基尼指数(Gini Index)- CART决策树

CART(Classification and Regression Tree)决策树使用基尼指数来选择划分属性。
数据集 D D D的纯度,用基尼值度量为:
G i n i ( D ) = ∑ k = 1 ∣ y ∣ ∑ k ′ ≠ k p k p k ′ = 1 − ∑ k = 1 ∣ y ∣ p k 2 Gini(D)=\sum_{k=1}^{|y|} \sum_{k'\not= k} p_kp_k'=1-\sum_{k=1}^{|y|}p_k^2 Gini(D)=k=1yk=kpkpk=1k=1ypk2
G i n i ( D ) Gini(D) Gini(D)的值越小,则 D D D的纯度越高。

属性a的基尼指数定义为:
G i n i _ i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D ) Gini\_index(D,a)= \sum_{v=1}^{V} \frac {|D^v|} {|D|} Gini(D) Gini_index(D,a)=v=1VDDvGini(D)
从属性集A中选择基尼指数最小的属性作为最优划分属性 a ∗ = a r g   m i n   a ∈ A G i n i _ i n d e x ( D , a ) a_*=\underset{a \in A}{arg\ min\ } Gini\_index(D,a) a=aAarg min Gini_index(D,a)

5.剪枝处理(Pruning)

剪枝处理是决策树算法处理“过拟合”的主要方式,即主动去掉一些分支来降低过拟合的风险。

朋友们可以自己补一下<奥卡姆剃刀准则>。
从机器学习这本书中拿几张图,理解一下:

【西瓜数据集】未剪枝决策树流程图,选择属性“脐部”来对训练集进行划分判别西瓜的好坏。

未剪枝

决策树剪枝有两种基本策略:

(1)预剪枝(prepruning)

预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点。

预剪枝

(2)后剪枝(postpruning)

后剪枝是指先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。
后剪枝

后剪枝决策树往往比预剪枝决策树保留更多的分支,一般情况下,后剪枝决策树的欠拟合风险较小,泛化能力往往优于预剪枝决策树。但后剪枝的训练时间比未剪枝和预剪枝都要长。

二、利用决策树进行鸢尾花数据集分类预测

sklearn中的决策树分类器

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, class_weight=None, ccp_alpha=0.0)
  • criterion : gini或者entropy,前者是基尼指数,后者是信息熵;
  • max_depth : int or None, optional (default=None) 设置决策随机森林中的决策树的最大深度,深度越大,越容易过拟合,推荐树的深度为:5-20之间;
  • max_features: None(所有),log2,sqrt,N 特征小于50的时候一般使用所有的;
  • max_leaf_nodes : 通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。

数据集划分api

sklearn.model_selection.train_test_split(arrays, *options)
  • 参数:
    x 数据集的特征值
    y 数据集的标签值
    test_size 测试集的大小,一般为float
    random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。
  • return
    x_train, x_test, y_train, y_test

代码如下(示例):

# pandas用于处理和分析数据
import pandas as pd
import numpy as np
# 导入鸢尾花数据集
from sklearn.datasets import load_iris
# 导入决策树分类器
from sklearn.tree import DecisionTreeClassifier
# # 导入分割数据集的方法
from sklearn.model_selection import train_test_split
# import relevant packages
from sklearn import tree
from sklearn.tree import export_text
# import matplotlib; matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# 利用决策树进行鸢尾花数据集分类预测
# 数据集字段说明:
# 特征值(4个):sepal length(花萼长度),sepal width(花萼宽度), petal length(花瓣长度),petal width(花瓣宽度)
# 目标值(3个):target(类别,0'setosa'山鸢尾花,1'versicolor'变色鸢尾花,2'virginica'维吉尼亚鸢尾花)

# load in the data加载数据
data = load_iris()
# convert to a dataframe 转换数据格式
df = pd.DataFrame(data.data, columns = data.feature_names)
# create the species column
df['Species'] = data.target

# replace this with the actual names
target = np.unique(data.target)  # 对于一维数组或者列表,unique函数去除其中重复的元素,并按元素由大到小返回一个新的无元素重复的元组或者列表
target_names = np.unique(data.target_names)
targets = dict(zip(target, target_names))
df['Species'] = df['Species'].replace(targets)

# extract features and target variables 提取特征和目标变量
x = df.drop(columns="Species")
y = df["Species"]
# save the feature name and target variables 保存特征名称和目标变量
feature_names = x.columns
labels = y.unique()  # 去除重复元素

# 分割训练集、测试集
# x 数据集的特征值
# y 数据集的标签值
# 训练集的特征值x_train 测试集的特征值x_test(test_x) 训练集的目标值y_train 测试集的目标值y_test(test_lab)
# random_state 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。
X_train, test_x, y_train, test_lab = train_test_split(x,y,
                                                 test_size = 0.4,
                                                 random_state = 42)
# 创建决策树分类器(树的最大深度为3)
model = DecisionTreeClassifier(max_depth =3, random_state = 42)  # 初始化模型
model.fit(X_train, y_train)  # 训练模型
print(model.score(test_x,test_lab))  # 评估模型分数
# 计算每个特征的重要程度
print(model.feature_importances_)

# 可视化特征属性结果
r = export_text(model, feature_names=data['feature_names'])
print(r)

# plt the figure, setting a black background
plt.figure(figsize=(30,10), facecolor ='g')  # facecolor设置背景色

# create the tree plot 决策树绘图模块,实现决策树可视化
a = tree.plot_tree(model,
                   # use the feature names stored
                   feature_names = feature_names,
                   # use the class names stored
                   class_names = labels,
                   # label='all',
                   rounded = True,
                   filled = True,
                   fontsize=14,
                   )
# show the plot
# plt.legend(loc='lower right', borderpad=0, handletextpad=0)
plt.savefig("save.png", dpi=300, bbox_inches="tight")
# plt.tight_layout()
plt.show()

决策树
输出结果:

0.9833333333333333
[0.         0.         0.58908421 0.41091579]
|--- petal length (cm) <= 2.45
|   |--- class: setosa
|--- petal length (cm) >  2.45
|   |--- petal width (cm) <= 1.75
|   |   |--- petal length (cm) <= 5.35
|   |   |   |--- class: versicolor
|   |   |--- petal length (cm) >  5.35
|   |   |   |--- class: virginica
|   |--- petal width (cm) >  1.75
|   |   |--- petal length (cm) <= 4.85
|   |   |   |--- class: virginica
|   |   |--- petal length (cm) >  4.85
|   |   |   |--- class: virginica
  • 30
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树是一种常用的分类算法,其C4.5决策树算法决策树的一种改进算法。下面是一个基于Python的C4.5决策树算法的实现示例: 首先,我们需要定义一个节点类,用于存储每个节点的信息和属性。 ```python class Node: def __init__(self, attribute=None, threshold=None, label=None, left=None, right=None): self.attribute = attribute # 属性名 self.threshold = threshold # 划分阈值 self.label = label # 叶子节点的类别 self.left = left # 左子节点 self.right = right # 右子节点 ``` 然后,我们需要定义一个C4.5决策树算法类,其包含以下方法: 1. `__init__`:初始化决策树模型。 2. `entropy`:计算数据集的熵。 3. `conditional_entropy`:计算数据集在某个属性上的条件熵。 4. `information_gain`:计算信息增益。 5. `majority_vote`:统计数据集出现最多的类别。 6. `build_tree`:构建决策树。 7. `predict`:预测新样本的类别。 ```python import numpy as np from collections import Counter class C45DecisionTree: def __init__(self, max_depth=5, min_samples_split=2): self.max_depth = max_depth # 最大深度 self.min_samples_split = min_samples_split # 最小分割样本数 def entropy(self, y): """计算数据集的熵""" counter = Counter(y) probs = [count / len(y) for count in counter.values()] return -sum(p * np.log2(p) for p in probs) def conditional_entropy(self, X, y, feature_idx, threshold): """计算数据集在某个属性上的条件熵""" left_mask = X[:, feature_idx] < threshold right_mask = X[:, feature_idx] >= threshold left_probs = len(y[left_mask]) / len(y) right_probs = len(y[right_mask]) / len(y) left_entropy = self.entropy(y[left_mask]) right_entropy = self.entropy(y[right_mask]) return left_probs * left_entropy + right_probs * right_entropy def information_gain(self, X, y, feature_idx, threshold): """计算信息增益""" parent_entropy = self.entropy(y) child_entropy = self.conditional_entropy(X, y, feature_idx, threshold) return parent_entropy - child_entropy def majority_vote(self, y): """统计数据集出现最多的类别""" counter = Counter(y) most_common = counter.most_common(1) return most_common[0][0] def build_tree(self, X, y, depth=0): """构建决策树""" # 判断是否达到最大深度或最小分割样本数 if depth >= self.max_depth or len(y) < self.min_samples_split: return Node(label=self.majority_vote(y)) n_features = X.shape[1] best_feature, best_threshold, best_gain = None, None, 0 for feature_idx in range(n_features): # 计算每个属性的信息增益 thresholds = np.unique(X[:, feature_idx]) for threshold in thresholds: gain = self.information_gain(X, y, feature_idx, threshold) if gain > best_gain: best_feature, best_threshold, best_gain = feature_idx, threshold, gain # 判断是否需要划分 if best_gain > 0: left_mask = X[:, best_feature] < best_threshold right_mask = X[:, best_feature] >= best_threshold left_node = self.build_tree(X[left_mask], y[left_mask], depth + 1) right_node = self.build_tree(X[right_mask], y[right_mask], depth + 1) return Node(attribute=best_feature, threshold=best_threshold, left=left_node, right=right_node) # 无法划分,返回叶子节点 return Node(label=self.majority_vote(y)) def predict(self, X): """预测新样本的类别""" node = self.root while node.label is None: if X[node.attribute] < node.threshold: node = node.left else: node = node.right return node.label ``` 最后,我们可以使用该算法对一个数据集进行分类。 ```python # 导入数据集 from sklearn.datasets import load_iris iris = load_iris() X = iris.data y = iris.target # 构建决策树 model = C45DecisionTree(max_depth=5, min_samples_split=2) model.root = model.build_tree(X, y) # 对新样本进行分类 new_sample = [5.0, 3.6, 1.3, 0.25] label = model.predict(new_sample) print(label) ``` 以上代码输出结果为 `0`,表示该新样本属于第一类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值