从零实现Decision Space:基于Decision Tree构建分区的Python技术问询
Python从零实现Decision Space的方案
核心思路
你的猜测完全正确:先将决策树转换为规则集,再基于规则构建空间分区是实现Decision Space的最直接路径。决策树的每个叶节点对应一条由路径上所有分裂条件组合而成的分类规则,每条规则恰好对应m维乘积空间中的一个闭合分区(完全符合有界偏序集的定义)。
实现步骤与代码示例
1. 决策树转规则集
假设你已实现的Node类结构如下(适配现有决策树代码):
class Node: def __init__(self): self.split_attr = None # 分裂属性名,如"age" self.split_val = None # 分裂阈值,如4 self.left = None # 左子节点(满足条件分支,如age<=4) self.right = None # 右子节点(不满足条件分支,如age>4) self.is_leaf = False # 是否为叶节点 self.label = None # 叶节点分类标签
编写递归函数遍历决策树,生成规则集:
def tree_to_rules(node, current_rule=None): if current_rule is None: current_rule = [] if node.is_leaf: # 叶节点:返回规则列表+对应分类标签 return [(current_rule.copy(), node.label)] # 左分支:添加"属性<=阈值"的条件 current_rule.append((node.split_attr, "<=", node.split_val)) left_rules = tree_to_rules(node.left, current_rule) current_rule.pop() # 右分支:添加"属性>阈值"的条件(离散属性可改为"==") current_rule.append((node.split_attr, ">", node.split_val)) right_rules = tree_to_rules(node.right, current_rule) current_rule.pop() return left_rules + right_rules
每条规则是条件列表,比如[("age", "<=", 4), ("degree", "<=", 2)],对应空间中一个矩形分区。
2. Decision Space类实现
class DecisionSpace: def __init__(self, attr_bounds): # attr_bounds: 字典,键为属性名,值为(min_val, max_val, comparator) # comparator定义偏序关系,比如数值型用lambda x,y: x <= y self.attr_bounds = attr_bounds self.dim = len(attr_bounds) self.partitions = [] # 存储分区:(规则条件, 分类标签, 空间区间) def _rule_to_interval(self, rule): # 将规则转换为m维空间的区间表示 interval = {} # 初始化每个属性的全空间(有界偏序集的最小/最大元) for attr, (min_val, max_val, _) in self.attr_bounds.items(): interval[attr] = [min_val, max_val] # 根据规则条件缩小区间 for attr, op, val in rule: if op == "<=": if val < interval[attr][1]: interval[attr][1] = val elif op == ">": if val > interval[attr][0]: interval[attr][0] = val # 离散属性可添加op=="=="的情况,设置区间为[val, val] return interval def build_partitions(self, decision_tree): # 从决策树生成规则集,再构建空间分区 rules = tree_to_rules(decision_tree) self.partitions = [] for rule, label in rules: interval = self._rule_to_interval(rule) self.partitions.append((rule, label, interval)) def map_point(self, data_point): # 将数据点映射到空间,返回所属分区的分类标签 for rule, label, interval in self.partitions: match = True for attr, op, val in rule: cmp_func = self.attr_bounds[attr][2] if op == "<=": if not cmp_func(data_point[attr], val): match = False break elif op == ">": if cmp_func(data_point[attr], val): match = False break if match: return label # 未匹配点(落在边界外,按有界偏序集定义归为默认分区) return None def visualize_2d(self, attr_x, attr_y): # 可视化二维空间分区(仅适用于m=2的场景) import matplotlib.pyplot as plt plt.figure(figsize=(8,6)) # 绘制每个分区的矩形边界 for rule, label, interval in self.partitions: x_min, x_max = interval[attr_x] y_min, y_max = interval[attr_y] rect = plt.Rectangle((x_min, y_min), x_max-x_min, y_max-y_min, fill=True, alpha=0.3, label=f"Label: {label}") plt.gca().add_patch(rect) # 设置坐标轴范围 plt.xlim(self.attr_bounds[attr_x][0], self.attr_bounds[attr_x][1]) plt.ylim(self.attr_bounds[attr_y][0], self.attr_bounds[attr_y][1]) plt.xlabel(attr_x) plt.ylabel(attr_y) plt.legend() plt.show()
3. 使用示例
假设你的决策树根节点以age=4分裂,左子节点以degree=2分裂:
# 初始化属性的有界偏序集(min/max取数据集极值) attr_bounds = { "age": (0, 10, lambda x,y: x <= y), "degree": (0, 5, lambda x,y: x <= y) } # 构建示例决策树 root = Node() root.split_attr = "age" root.split_val = 4 left_node = Node() left_node.split_attr = "degree" left_node.split_val = 2 left_leaf1 = Node() left_leaf1.is_leaf = True left_leaf1.label = "Class A" left_node.left = left_leaf1 left_leaf2 = Node() left_leaf2.is_leaf = True left_leaf2.label = "Class B" left_node.right = left_leaf2 right_leaf = Node() right_leaf.is_leaf = True right_leaf.label = "Class C" root.right = right_leaf # 初始化DecisionSpace并构建分区 ds = DecisionSpace(attr_bounds) ds.build_partitions(root) # 测试数据点映射 test_point = {"age": 3, "degree": 1} print(ds.map_point(test_point)) # 输出: Class A # 可视化二维分区 ds.visualize_2d("age", "degree")
关键说明
- 有界偏序集实现:通过
attr_bounds中的min/max定义最小元和最大元,comparator函数定义偏序关系,兼容数值型、离散型等不同属性类型。 - 通用性扩展:如果需要支持复杂偏序(如离散属性的层级关系),只需修改
_rule_to_interval和map_point中的条件判断逻辑即可,相比决策树灵活性更强。
内容的提问来源于stack exchange,提问作者GGT
相关产品推荐
相关产品推荐

