Python递归实现决策树算法
决策树算法是一种常用的机器学习算法,它可以用于分类、回归等任务。在本文中,我们将使用Python语言实现决策树算法,并通过一个例子来说明该算法的具体实现过程。
首先,我们需要定义一个决策树的数据结构,通常我们使用字典来表示决策树。对于一个二叉树结构的节点,包含以下信息:
- 当前节点的分裂特征
- 当前节点的分裂点阈值(如果是离散特征,则没有该值)
- 左子树(小于分裂点的样本)对应的节点,如果该节点是叶子节点,则保存当前节点所属的类别
- 右子树(大于等于分裂点的样本)对应的节点,如果该节点是叶子节点,则保存当前节点所属的类别
根据上面的定义,我们可以按照如下方式来定义一个决策树节点:
class DecisionTree: def __init__(self, criteria=None, threshold=None, left=None, right=None, value=None): self.criteria = criteria # 分裂特征 self.threshold = threshold # 分裂点阈值 self.left = left # 左子节点 self.right = right # 右子节点 self.value = value # 叶子节点的值
接下来,我们需要实现决策树算法,具体实现过程如下:
- 判断当前节点是否为叶子节点,如果是叶子节点,则直接返回该节点的值;
- 否则,根据当前节点的分裂特征和分裂点阈值对样本进行划分,将小于分裂点阈值的样本划分到左子树,大于等于分裂点阈值的样本划分到右子树;
- 递归地对左子树和右子树调用决策树算法,返回左右子树的值。
具体实现代码如下所示:
def decision_tree(X, y, max_depth=5, feature_type='continuous'): n_samples, n_features = X.shape # 计算数据集中每个类别的样本数目 class_cnt = Counter(y) # 当前节点为叶子节点,返回该节点所属类别 if len(class_cnt) == 1: return DecisionTree(value=list(class_cnt.keys())[0]) # 没有可用特征或到达最大深度,选择出现次数最多的类别作为当前节点所属类别 if n_features == 0 or max_depth == 0: return DecisionTree(value=max(class_cnt, key=class_cnt.get)) # 选择最佳分裂特征和阈值 best_criteria, best_threshold = choose_best_criteria(X, y, feature_type) # 生成左右子树 left_idx = X[:, best_criteria] < best_threshold left_tree = decision_tree(X[left_idx], y[left_idx], max_depth-1, feature_type) right_tree = decision_tree(X[~left_idx], y[~left_idx], max_depth-1, feature_type) # 返回决策树 return DecisionTree(criteria=best_criteria, threshold=best_threshold, left=left_tree, right=right_tree)
在上面的实现中,我们使用了choose_best_criteria()
函数来选择最佳的分裂特征和阈值,这里我们只给出代码实现的概要:
def choose_best_criteria(X, y, feature_type): # 根据不同的特征类型使用不同的分裂策略 if feature_type == 'continuous': ... elif feature_type == 'discrete': ... else: raise ValueError('Unsupported feature type: %s' % feature_type) # 返回最佳分裂特征和阈值 return best_criteria, best_threshold
最后,我们使用一个简单的例子来演示决策树算法的实现过程。假设我们有如下一些样本:
X = np.array([[0, 1, 1, 0], [1, 0, 0, 0], [0, 1, 0, 1], [1, 0, 1, 1], [0, 1, 1, 1], [1, 0, 0, 1], [0, 0, 1, 1]]) y = np.array([0, 0, 1, 0, 1, 1, 1])
其中,特征0表示是否为“pidancode.com”,特征1表示是否为“皮蛋编程”,特征2表示是否含有数字,特征3表示是否含有大写字母。现在我们使用以上代码创建决策树:
tree = decision_tree(X, y, max_depth=2, feature_type='discrete')
其中,我们设置了最大深度为2,只使用离散特征进行分裂。得到的决策树如下所示:
分裂特征2=0/1 / \ 分裂特征1=0/1 分裂特征0=0/1 / \ / \ 叶节点(0) 叶节点(1) 叶节点(0) 叶节点(1)
这棵决策树共生成了4个节点(包括3个叶节点),它可以用于对新样本进行分类。
实际应用中,我们还需要对决策树进行剪枝、调参等操作,以获得更好的效果。此外,决策树算法还可以扩展为随机森林、梯度提升树等更复杂的模型,可以用于更高级别的任务。
相关文章