决策树原理
决策树是一种树形结构,其中每个节点代表一个特征或属性,每个分支代表一个决策结果,每个叶节点代表一个类别(在分类问题中)或一个数值(在回归问题中)。
决策树的构建过程可以形象地理解为:在每个节点,我们都会考察一个特征,根据这个特征的不同取值,我们选择一个分支继续往下走。这样一直走下去,直到到达一个叶节点,也就是决策结果。
例如,如果我们有一组水果数据,其中包括“外观”、“颜色”、“口感”等特征,我们想根据这些特征来预测水果是否甜美。我们可以构建一个决策树,其中每个节点都是一个特征,每个分支代表一个可能的决策结果(比如“甜”或“不甜”),每个叶节点就是最终的预测结果。
在构建决策树时,我们需要考虑如何选择最佳的特征来进行划分。通常,我们使用一些指标来评估特征划分的好坏,比如信息增益、基尼指数等。这些指标可以衡量划分后的子集的纯度(即每个子集中同类样本的比例)以及划分后的信息熵(即样本的不确定性)。
通过不断选择最优特征进行划分,我们可以构建出一棵最优的决策树,使得每个叶节点的数据尽可能同类聚集,不同类样本尽量分散。这样,我们就可以用这棵决策树来预测新的样本是属于哪个类别或哪个数值。
完整代码
import numpy as np
class DecisionTree:
def __init__(self):
self.tree = None
def entropy(self, y):
"""
计算信息熵。
Parameters:
y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
Returns:
float: 信息熵。
"""
unique, counts = np.unique(y, return_counts=True)
probabilities = counts / len(y)
return -np.sum(probabilities * np.log2(probabilities))
def information_gain(self, X, y, feature_index, threshold):
"""
计算信息增益。
Parameters:
X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
feature_index (int): 特征的索引。
threshold (float): 特征的阈值。
Returns:
float: 信息增益。
"""
total_entropy = self.entropy(y)
# 将数据根据特征和阈值划分为两个子集
left_mask = X[:, feature_index] <= threshold
right_mask = ~left_mask
left_entropy = self.entropy(y[left_mask])
right_entropy = self.entropy(y[right_mask])
# 计算加权平均的信息熵
subset_entropy = (len(y[left_mask]) / len(y)) * left_entropy + (len(y[right_mask]) / len(y)) * right_entropy
return total_entropy - subset_entropy
def find_best_split(self, X, y):
"""
寻找最佳的切分特征和阈值。
Parameters:
X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
Returns:
tuple: 包含最佳切分特征的索引和最佳阈值。
"""
best_feature_index = None
best_threshold = None
max_information_gain = -1
for feature_index in range(X.shape[1]):
unique_values = np.unique(X[:, feature_index])
thresholds = (unique_values[:-1] + unique_values[1:]) / 2
for threshold in thresholds:
information_gain = self.information_gain(X, y, feature_index, threshold)
if information_gain > max_information_gain:
max_information_gain = information_gain
best_feature_index = feature_index
best_threshold = threshold
return best_feature_index, best_threshold
def build_tree(self, X, y, depth=0, max_depth=None):
"""
递归地构建决策树。
Parameters:
X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
depth (int): 当前节点的深度。
max_depth (int): 树的最大深度。
Returns:
dict: 决策树的节点信息。
"""
unique, counts = np.unique(y, return_counts=True)
majority_class = unique[np.argmax(counts)]
# 如果样本纯净或达到最大深度,则创建叶节点
if len(unique) == 1 or (max_depth is not None and depth == max_depth):
return {'class': majority_class, 'depth': depth}
# 寻找最佳的切分特征和阈值
best_feature_index, best_threshold = self.find_best_split(X, y)
# 如果无法找到切分点,则创建叶节点
if best_feature_index is None:
return {'class': majority_class, 'depth': depth}
# 根据最佳切分特征和阈值划分数据
left_mask = X[:, best_feature_index] <= best_threshold
right_mask = ~left_mask
# 递归地构建左右子树
left_subtree = self.build_tree(X[left_mask], y[left_mask], depth + 1, max_depth)
right_subtree = self.build_tree(X[right_mask], y[right_mask], depth + 1, max_depth)
return {
'feature_index': best_feature_index,
'threshold': best_threshold,
'left': left_subtree,
'right': right_subtree,
'depth': depth
}
def fit(self, X, y, max_depth=None):
"""
训练决策树模型。
Parameters:
X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
y (numpy.ndarray): 输出变量,每个元素对应于相应样本的输出。
max_depth (int): 树的最大深度。
Returns:
None
"""
self.tree = self.build_tree(X, y, max_depth=max_depth)
def predict_single(self, x, node):
"""
预测单个样本的类别。
Parameters:
x (numpy.ndarray): 单个样本的特征。
node (dict): 决策树节点信息。
Returns:
int: 预测的类别。
"""
if 'class' in node:
return node['class']
if x[node['feature_index']] <= node['threshold']:
return self.predict_single(x, node['left'])
else:
return self.predict_single(x, node['right'])
def predict(self, X):
"""
预测多个样本的类别。
Parameters:
X (numpy.ndarray): 输入特征矩阵,每行代表一个样本,每列代表一个特征。
Returns:
numpy.ndarray: 预测的类别。
"""
return np.array([self.predict_single(x, self.tree) for x in X])
# 示例用法
if __name__ == "__main__":
# 准备数据
X_train = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
y_train = np.array([0, 0, 1, 1, 1])
# 创建决策树模型
model = DecisionTree()
# 训练模型
model.fit(X_train, y_train)
# 预测新数据
X_new = np.array([[3, 3]])
predictions = model.predict(X_new)
print(f'预测类别:{predictions}')