我目前正在使用Gini和信息增益制作一个决策树分类器,并根据每次增益最大的最佳属性来分裂树。然而,每次它都坚持使用同一个属性,并且只是调整其问题的值。这导致准确率非常低,通常约为30%,因为它只考虑了第一个属性。
寻找最佳分裂
# 用于在所有属性中寻找数据的最佳分裂def split(r): max_ig = 0 max_att = 0 max_att_val = 0 i = 0 curr_gini = gini_index(r) n_att = len(att) for c in range(n_att): if c == 3: continue c_vals = get_column(r, c) while i < len(c_vals): # 正在测试的当前属性的值 curr_att_val = r[i][c] true, false = fork(r, c, curr_att_val) ig = gain(true, false, curr_gini) if ig > max_ig: max_ig = ig max_att = c max_att_val = r[i][c] i += 1 return max_ig, max_att, max_att_val
根据真或假比较以分裂数据
# 用于比较并测试当前行是否大于或等于测试值# 以便分裂数据def compare(r, test_c, test_val): if r[test_c].isdigit(): return r[test_c] == test_val elif float(r[test_c]) >= float(test_val): return True else: return False# 将数据分裂成两个列表以表示比较测试的真/假结果def fork(r, c, test_val): true = [] false = [] for row in r: if compare(row, c, test_val): true.append(row) else: false.append(row) return true, false
遍历树
def rec_tree(r):ig, att, curr_att_val = split(r)if ig == 0: return Leaf(r)true_rows, false_rows = fork(r, att, curr_att_val)true_branch = rec_tree(true_rows)false_branch = rec_tree(false_rows)return Node(att, curr_att_val, true_branch, false_branch)
回答:
我找到的工作解决方案是如下更改split函数。老实说,我看不出哪里出了问题,但这可能很明显。工作函数如下
def split(r):max_ig = 0max_att = 0max_att_val = 0# 计算提供行的Gini值curr_gini = gini_index(r)no_att = len(r[0])# 遍历不同的属性for c in range(no_att): # 跳过标签列(啤酒风格) if c == 3: continue column_vals = get_column(r, c) i = 0 while i < len(column_vals): # 我们想要检查的值 att_val = r[i][c] # 使用属性值将数据分叉到真和假流 true, false = fork(r, c, att_val) # 计算信息增益 ig = gain(true, false, curr_gini) # 如果这个增益是找到的最高增益,则标记为最佳选择 if ig > max_ig: max_ig = ig max_att = c max_att_val = r[i][c] i += 1return max_ig, max_att, max_att_val