决策树是一种用于分类和回归任务的监督学习算法,它以树形结构递归地将数据分割成不同区域,使得最终的预测值尽可能纯净(即减少分类问题中的混杂度,或回归问题中的误差)。决策树算法简单直观、易于理解、解释性强,广泛应用于各类场景。本教程将详细介绍决策树的原理,重点解析构建决策树过程中的关键概念及其实现。
决策树的基本原理
决策树基于"树"结构构建模型,其中:
- 根节点代表整个数据集。
- 分支表示不同的特征条件分割路径。
- 叶节点是最终的类别(或预测值)。
决策树的构建过程通过递归地选择最佳特征来分割数据,直到满足某个终止条件(如达到最大深度或叶节点纯度)。在决策树中,每次分割的数据称为"分支",直到数据被分割成多个不相交的区域为止。
决策树的分割准则
常用的决策树分割准则包括:
- 分类问题 中常用的指标:
- 信息增益:基于信息熵计算,用于评估特征对数据的纯度贡献。
- 基尼系数:用于衡量数据集的混乱程度。
- 回归问题 中常用的指标:
- 均方误差(MSE):用于最小化预测值与实际值的平方差。
- 均绝对误差(MAE):用于最小化预测值与实际值的绝对差。
构建决策树的步骤
- 选择最优特征进行分裂:根据指标(如信息增益或基尼系数)选择最优特征分割数据。
- 递归分割:对子节点继续分割,直到满足停止条件。
- 生成叶节点:一旦满足停止条件,不再继续分割,将该节点标记为叶节点。
信息增益与基尼系数的计算
信息熵和信息增益
**信息熵(Entropy)**衡量了数据的纯度或混乱度,熵越小数据越纯。对于一个二分类问题的标签 ( Y ),若其取值为 ( 0 ) 和 ( 1 ) 的概率分别为 ( p ) 和 ( 1 - p ),信息熵公式如下:
H ( Y ) = − ∑ p i log 2 p i H(Y) = - \sum p_i \log_2 p_i H(Y)=−∑pilog2pi
信息增益表示分割前后信息熵的减少量,用于选择最佳分割特征。
基尼系数(Gini Impurity)
基尼系数 是另一种衡量混乱度的方法,其公式如下:
G ( Y ) = 1 − ∑ p i 2 G(Y) = 1 - \sum p_i^2 G(Y)=1−∑pi2
其中 ( p_i ) 为第 ( i ) 类的概率。基尼系数越小,数据集的纯度越高。
用 Numpy 实现决策树(分类)
以下代码展示了如何用 Numpy 实现简单的决策树,基于基尼系数选择最优分裂特征。
python
import numpy as np
import matplotlib.pyplot as plt
# 定义基尼系数计算函数
def gini_impurity(y):
_, counts = np.unique(y, return_counts=True)
probabilities = counts / counts.sum()
return 1 - np.sum(np.square(probabilities))
# 基于特征划分数据集
def split_dataset(X, y, feature, threshold):
left_mask = X[:, feature] <= threshold
right_mask = ~left_mask
return X[left_mask], y[left_mask], X[right_mask], y[right_mask]
# 查找最佳分割点
def best_split(X, y):
best_gini = 1
best_feature, best_threshold = None, None
for feature in range(X.shape[1]):
thresholds = np.unique(X[:, feature])
for threshold in thresholds:
_, y_left, _, y_right = split_dataset(X, y, feature, threshold)
if len(y_left) == 0 or len(y_right) == 0:
continue
gini_left = gini_impurity(y_left)
gini_right = gini_impurity(y_right)
gini_split = (len(y_left) * gini_left + len(y_right) * gini_right) / len(y)
if gini_split < best_gini:
best_gini = gini_split
best_feature = feature
best_threshold = threshold
return best_feature, best_threshold, best_gini
# 决策树类
class DecisionTree:
def __init__(self, max_depth=3):
self.max_depth = max_depth
self.tree = None
def fit(self, X, y, depth=0):
feature, threshold, gini = best_split(X, y)
if feature is None or depth >= self.max_depth:
return np.argmax(np.bincount(y))
left_X, left_y, right_X, right_y = split_dataset(X, y, feature, threshold)
left_node = self.fit(left_X, left_y, depth + 1)
right_node = self.fit(right_X, right_y, depth + 1)
self.tree = {"feature": feature, "threshold": threshold, "left": left_node, "right": right_node}
return self.tree
def predict_sample(self, x, tree):
if not isinstance(tree, dict):
return tree
if x[tree["feature"]] <= tree["threshold"]:
return self.predict_sample(x, tree["left"])
else:
return self.predict_sample(x, tree["right"])
def predict(self, X):
return np.array([self.predict_sample(x, self.tree) for x in X])
# 数据生成
X = np.array([[2, 3], [1, 1], [3, 2], [4, 3], [3, 4]])
y = np.array([0, 0, 1, 1, 0])
# 训练决策树
tree = DecisionTree(max_depth=3)
tree.fit(X, y)
# 预测并可视化
preds = tree.predict(X)
print("预测结果:", preds)
# 可视化决策边界
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm')
plt.xlabel("特征 1")
plt.ylabel("特征 2")
plt.title("决策树分割示意图")
plt.show()
在 Sklearn 中使用决策树
在 Sklearn 中,我们可以直接使用 DecisionTreeClassifier
和 DecisionTreeRegressor
来进行分类和回归任务,简化了构建和预测流程。
python
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 训练决策树
clf = DecisionTreeClassifier(max_depth=3)
clf.fit(X, y)
# 预测
preds_sklearn = clf.predict(X)
print("Sklearn 预测结果:", preds_sklearn)
# 计算准确率
accuracy = accuracy_score(y, preds_sklearn)
print("准确率:", accuracy)
总结
本文从基本原理出发,详细介绍了决策树的分割准则及构建流程,并使用 Numpy 实现了一个基础的决策树分类器,最后展示了在 Sklearn 中使用决策树的便捷方式。决策树算法易于理解且解释性强,在多种任务中应用广泛,适合初学者掌握和使用。