在sklearn DecisionTreeClassifier中修剪不必要的叶子

Tho*_*mas 4 python decision-tree pruning scikit-learn

我使用sklearn.tree.DecisionTreeClassifier来构建决策树.使用最佳参数设置,我得到一个有不必要叶子的树(参见下面的示例图片 - 我不需要概率,所以标记为红色的叶节点是不必要的分割)

树

是否有任何第三方库用于修剪这些不必要的节点?还是代码片段?我可以写一个,但我无法想象我是第一个有这个问题的人......

要复制的代码:

from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
mdl = DecisionTreeClassifier(max_leaf_nodes=8)
mdl.fit(X,y)
Run Code Online (Sandbox Code Playgroud)

PS:我尝试了多次关键词搜索,并且很惊讶地发现什么都没有 - 在sklearn中是否真的没有后期修剪?

PPS:响应可能的重复:虽然建议的问题可能对我自己编码修剪算法有帮助,但它回答了一个不同的问题 - 我想摆脱不改变最终决定的叶子,而另一个问题想要一个拆分节点的最小阈值.

PPPS:显示的树是一个显示我的问题的例子.我知道创建树的参数设置不是最理想的.我不是要求优化这个特定的树,我需要进行后修剪以摆脱可能有用的叶子,如果一个人需要类概率,但如果一个人只对最可能的类感兴趣则没有帮助.

Tho*_*mas 6

使用ncfirth的链接,我能够修改那里的代码,以便它适合我的问题:

from sklearn.tree._tree import TREE_LEAF

def is_leaf(inner_tree, index):
    # Check whether node is leaf node
    return (inner_tree.children_left[index] == TREE_LEAF and 
            inner_tree.children_right[index] == TREE_LEAF)

def prune_index(inner_tree, decisions, index=0):
    # Start pruning from the bottom - if we start from the top, we might miss
    # nodes that become leaves during pruning.
    # Do not use this directly - use prune_duplicate_leaves instead.
    if not is_leaf(inner_tree, inner_tree.children_left[index]):
        prune_index(inner_tree, decisions, inner_tree.children_left[index])
    if not is_leaf(inner_tree, inner_tree.children_right[index]):
        prune_index(inner_tree, decisions, inner_tree.children_right[index])

    # Prune children if both children are leaves now and make the same decision:     
    if (is_leaf(inner_tree, inner_tree.children_left[index]) and
        is_leaf(inner_tree, inner_tree.children_right[index]) and
        (decisions[index] == decisions[inner_tree.children_left[index]]) and 
        (decisions[index] == decisions[inner_tree.children_right[index]])):
        # turn node into a leaf by "unlinking" its children
        inner_tree.children_left[index] = TREE_LEAF
        inner_tree.children_right[index] = TREE_LEAF
        ##print("Pruned {}".format(index))

def prune_duplicate_leaves(mdl):
    # Remove leaves if both 
    decisions = mdl.tree_.value.argmax(axis=2).flatten().tolist() # Decision for each node
    prune_index(mdl.tree_, decisions)
Run Code Online (Sandbox Code Playgroud)

在DecisionTreeClassifier clf上使用它:

prune_duplicate_leaves(clf)
Run Code Online (Sandbox Code Playgroud)

编辑:修复了更复杂树木的错误

  • 请注意,此代码将就地修改树。就本质而言,这还不错,如果您想比较树的修剪前/后修剪,就很容易知道了。 (2认同)