一、什么是决策树
决策树是一种基于树形结构的机器学习模型,用于进行分类和回归任务。它通过一系列的决策节点和分支来对数据进行分类或预测。决策树的每个节点表示一个特征,每个分支表示该特征可能的取值,而每个叶子节点则表示一个类别(对于分类任务)或一个数值(对于回归任务)。
在分类任务中,决策树通过对数据进行分裂,将其划分为不同的类别。在每个节点上,决策树根据某个特征的取值将数据分割成子集,然后递归地对每个子集进行进一步的分裂,直到满足停止条件,例如节点中的样本都属于同一类别或达到了树的最大深度。
在回归任务中,决策树通过对数据进行分裂,预测连续型的数值。与分类任务类似,决策树根据特征的取值将数据分割成子集,并递归地对每个子集进行进一步的分裂,直到满足停止条件,例如达到了树的最大深度或分裂后的子集样本数量不足。
决策树的优点包括易于理解和解释,对缺失值不敏感,并且能够处理各种类型的数据(例如数值型、类别型等)。然而,决策树也容易过拟合训练数据,特别是在处理复杂的问题时。因此,通常会通过剪枝等技术来避免过拟合。
二、决策树的作用
-
分类:决策树可以用于分类任务,即根据输入数据的特征将其分到不同的类别中。例如,可以使用决策树来判断一封电子邮件是否为垃圾邮件。
-
回归:除了分类,决策树还可以用于回归任务,即预测连续型的数值。例如,可以使用决策树来预测房屋的销售价格。
-
特征选择:决策树可以根据特征的重要性来选择最相关的特征,从而帮助理解数据并提高模型性能。
-
数据探索:通过可视化决策树,可以直观地了解数据的结构和特征之间的关系,从而发现数据中的模式和规律。
-
集成学习:决策树是许多集成学习算法的基础,如随机森林和梯度提升树。这些算法通过组合多个决策树来提高整体模型的性能和稳定性。
总的来说,决策树是一种灵活而强大的机器学习模型,可以用于各种类型的任务,包括分类、回归、特征选择和数据探索。
三、构建决策树的方法
(一)ID3 (Iterative Dichotomiser 3)
特征选择:ID3算法使用信息增益来选择最佳的特征进行分裂。信息增益衡量了选择某个特征进行分裂后,对于减少数据的不确定性所做的贡献。具体而言,算法计算每个特征的信息增益,选择具有最大信息增益的特征作为当前节点的分裂特征。
树的构建:根据信息增益进行递归地构建树形结构,直到满足停止条件,例如节点中的样本都属于同一类别,或者达到了树的最大深度。
(二)C4.5
特征选择:C4.5算法使用信息增益比来选择最佳的特征进行分裂。信息增益比考虑了特征的取值数目对信息增益的影响,避免了偏向取值较多的特征。具体而言,算法计算每个特征的信息增益比,选择具有最大信息增益比的特征作为当前节点的分裂特征。
树的构建:根据信息增益比进行递归地构建树形结构,直到满足停止条件,例如节点中的样本都属于同一类别,或者达到了树的最大深度。
(三)CART (Classification and Regression Trees)
特征选择:对于分类任务,CART算法使用基尼不纯度来选择最佳的特征进行分裂。基尼不纯度衡量了从数据集中随机抽取两个样本,它们属于不同类别的概率。具体而言,算法计算每个特征的基尼不纯度,选择具有最小基尼不纯度的特征作为当前节点的分裂特征。对于回归任务,CART算法使用均方差(Mean Squared Error)来衡量分裂的效果。
树的构建:根据基尼不纯度或均方差进行递归地构建树形结构,直到满足停止条件,例如节点中的样本都属于同一类别或达到了树的最大深度。
四、基于原理的具体公式实现
(一)信息熵
(二)信息增益
(三)信息增益率
五、实验代码呈现(肉食性与草食性动物的区分)
(一)实验总体代码
(有自己实现构建树的函数,后半部分使用了库中函数)
import numpy as np
import math
class Node:
def __init__(self, attribute=None, value=None, result=None):
self.attribute = attribute # 属性名
self.value = value # 分裂值(如果是叶节点则为None)
self.result = result # 类别结果(如果是内部节点则为None)
self.children = {} # 子节点字典,键为属性值,值为子节点
class DecisionTree:
def __init__(self):
self.root = None
def fit(self, X, y):
attributes = [i for i in range(len(X[0]))] # 特征属性列表
self.root = self._build_tree(X, y, attributes)
def _entropy(self, y):
# 计算给定数据集y的熵
classes = set(y)
entropy = 0
total = len(y)
for c in classes:
p = list(y).count(c) / total
entropy -= p * math.log2(p)
return entropy
def _information_gain(self, X, y, attribute):
# 计算使用给定属性attribute对数据集X进行划分所得的信息增益
values = set(X[:, attribute])
gain = self._entropy(y)
total = len(y)
for value in values:
subset_y = [y[i] for i in range(total) if X[i][attribute] == value]
gain -= len(subset_y) / total * self._entropy(subset_y)
return gain
def _build_tree(self, X, y, attributes):
# 递归构建决策树
if len(set(y)) == 1: # 如果所有样本属于同一类别,则创建叶节点并返回
return Node(result=y[0])
if len(attributes) == 0: # 如果没有可用属性,则创建叶节点并返回
return Node(result=int(np.argmax(np.bincount(y))))
best_attribute = max(attributes, key=lambda a: self._information_gain(X, y, a))
node = Node(attribute=best_attribute)
values = set(X[:, best_attribute])
for value in values:
subset_indices = [i for i in range(len(X)) if X[i][best_attribute] == value]
subset_X = X[subset_indices]
subset_y = [y[i] for i in subset_indices]
if len(subset_X) == 0: # 如果子集为空,则创建叶节点并返回
node.children[value] = Node(result=int(np.argmax(np.bincount(y))))
else:
subset_attributes = [a for a in attributes if a != best_attribute]
node.children[value] = self._build_tree(subset_X, subset_y, subset_attributes)
return node
def predict(self, X):
# 对输入的数据集X进行预测
predictions = []
for instance in X:
predictions.append(self._predict_instance(instance, self.root))
return predictions
def _predict_instance(self, instance, node):
# 对单个实例instance进行预测
if node.result is not None: # 如果是叶节点,则返回类别结果
return node.result
else:
value = instance[node.attribute]
if value in node.children:
return self._predict_instance(instance, node.children[value])
else: # 如果实例的属性值在训练集中未出现,则返回叶节点中出现频率最高的类别
return int(np.argmax(np.bincount(node.result)))
# 构建样本数据
X = np.array([
[1, 1, 1, 1], # 有尖牙,是哺乳动物,有爪子,是大型动物,是肉食动物
[1, 1, 0, 1], # 有尖牙,是哺乳动物,无爪子,是大型动物,是肉食动物
[0, 1, 1, 1], # 无尖牙,是哺乳动物,有爪子,是大型动物,是肉食动物
[0, 1, 0, 1], # 无尖牙,是哺乳动物,无爪子,是大型动物,是草食动物
[0, 0, 1, 0], # 无尖牙,不是哺乳动物,有爪子,不是大型动物,是草食动物
[0, 0, 0, 0] # 无尖牙,不是哺乳动物,无爪子,不是大型动物,是草食动物
])
y = np.array([1, 1, 1, 0, 0, 0])
# 创建并训练决策树模型
model = DecisionTree()
model.fit(X, y)
new_samples = np.array([
[1, 0, 1, 1], # 有尖牙,不是哺乳动物,有爪子,是大型动物
[1, 1, 0, 0], # 有尖牙,是哺乳动物,无爪子,是大型动物
[0, 1, 0, 0] # 无尖牙,是哺乳动物,无爪子,不是大型动物
])
predictions = model.predict(new_samples)
print("预测结果:", predictions)