为啥在导出的决策树中只​​标记父节点的边缘

Posted

技术标签:

【中文标题】为啥在导出的决策树中只​​标记父节点的边缘【英文标题】:Why are only the parent node's edges labelled in exported Decision Tree为什么在导出的决策树中只​​标记父节点的边缘 【发布时间】:2018-11-18 10:37:25 【问题描述】:

我有一个训练有素的 DecisionTreeClassifier 实例,我实际上对底层决策树本身的谓词很感兴趣。所以我需要一种干净的方式来遍历这棵树。

因为获得可遍历表示的唯一官方方法是使用 scikit 的 export_graphviz 函数导出到 graphviz/dot 文件。之后,我可以使用例如解析和分析树的图形表示。 networkx 和 pydot 的组合。

但是……

我的特定点文件的内容如下:

digraph Tree 

node [shape=box] ;

0 [label="X[0] <= 15.0\ngini = 0.75\nsamples = 8\nvalue = [2, 2, 2, 2]"] ;

1 [label="X[1] <= 3.0\ngini = 0.5\nsamples = 4\nvalue = [2, 0, 2, 0]"] ;

0 -> 1 [labeldistance=2.5, labelangle=45, headlabel="True"] ;

2 [label="gini = 0.0\nsamples = 2\nvalue = [0, 0, 2, 0]"] ;

1 -> 2 ;

3 [label="gini = 0.0\nsamples = 2\nvalue = [2, 0, 0, 0]"] ;

1 -> 3 ;

4 [label="X[1] <= 3.0\ngini = 0.5\nsamples = 4\nvalue = [0, 2, 0, 2]"] ;

0 -> 4 [labeldistance=2.5, labelangle=-45, headlabel="False"] ;

5 [label="gini = 0.0\nsamples = 2\nvalue = [0, 0, 0, 2]"] ;

4 -> 5 ;

6 [label="gini = 0.0\nsamples = 2\nvalue = [0, 2, 0, 0]"] ;

4 -> 6 ;


所以这看起来一切都很好,但为什么只有连接到父节点的边正确地用布尔值标记?该图中的所有边不应该都附有适当的布尔标签/属性吗??

或者,如果有一些奇怪的 graphviz/dot 约定可以帮助我区分后续的兄弟边,那么规则是什么?

我从 scikit 的 documentation on the decision tree classifier 中注意到,示例渲染的 graphviz 决策树实际上也缺少布尔标签。就我对决策树的了解而言,这遗漏了有关决策树的重要信息。还有什么我在这里遗漏的约定吗?例如。左边缘总是隐含地为真吗?由于它是垂直组织的,我如何从 dot 文件中分辨出来?

【问题讨论】:

我可以建议您删除graphvizdot 标签吗? graphviz 只做它被告知的事情,只要源代码不包含边缘标签,它就不会显示任何东西,正如人们所期望的那样。 但是我为什么要删除更多的标签呢?标签包含我的树的实际相关元数据。如果有的话,我想要更多的标签,而不是更少:) 添加或删除,关键是如果您的代码生成应用程序不为您执行此操作,您将不得不手动执行此操作。 graphviz 遵循它得到的说明,你的问题在之前的水平上。 啊,好的。我现在明白你的意思了。但我只对点文件感兴趣,因为我认为这是获得树的(尽管是序列化的)表示的唯一官方方式。我并不关心最终用 graphviz 渲染我的树。我现在明白有一种不同的 Pythonic 方法可以从 DecisionTreeClassifier 中获取结构。是的,如果我真的想要,我现在可以自己将这些额外的布尔标签添加到点文件中。 【参考方案1】:

在偶然发现 scikit-learn 网站上的一个示例后,我意识到我不必解析导出的点文件来获取 Python 树结构来表示我构建的决策树。显然我可以使用DecisionTreeClassifier 实例的tree_ 属性,这是根据official API reference (一直在底部)的暴露属性,它有一个关于如何使用这个tree_ 对象@ 的文档示例987654322@.

然而,这很令人困惑——至少对我而言——显然这个树对象是作为DecisionTreeClassifier API 的一部分公开的,并且它有一个关于如何以特定方式使用它的文档示例,但没有正式的已发布其基础类sklearn.tree._tree.Tree 的文档。你只需要查看源代码。

关于点文件,我现在很确定它的唯一目的就是渲染决策树。在查看source code of export_graphviz 之后,这个结论得到了重申,我注意到它确实是硬编码的,只传递连接到父节点的边缘标签。 export_graphviz 正在使用DecisionTreeClassifiertree_ 属性。从这个属性的使用方式来看,我认为你可以安全地推断出它总是先写出“真”边,然后再写出任何节点的“假”边。恕我直言,这保证了功能请求允许在给定参数标志的情况下标记所有边缘。

【讨论】:

你有没有想过解决这个问题? 所以我基本上遵循了上面'here' link中举例说明的想法。 This *** post 还展示了做我想做的各种方式。但是当我第一次偶然发现那篇文章时,我想到了破解的解决方案。但显然这就是 scikit 暴露其树对象内部的方式。

以上是关于为啥在导出的决策树中只​​标记父节点的边缘的主要内容,如果未能解决你的问题,请参考以下文章

请告诉我如何在决策树中拆分数字列或节点[关闭]

在二叉搜索树中找到一个节点的父节点

CART 决策树中的冲突拆分

二叉树中两个节点的第一个祖先父节点

在完美二叉树中获取顶点的父节点

从 Angular 6 材质树中的子节点获取父层次结构