如何获取 scikit-learn 决策树所有节点的 pos/neg 实例计数?

How to get pos/neg instance counts for all nodes of a scikit-learn decision tree?

我训练了一个 sklearn 决策树。

from sklearn.tree import DecisionTreeClassifier
c=DecisionTreeClassifier(class_weight="auto")
c.fit([[0,0],
       [0,1],
       [1,1],
      ],[0,1,0])

现在我想检查每个节点有多少 positive/negative 个样本。因此像

这样的图
  counts: [2,1]            labels: (010)
                                 split by x0
    [1,1]       [1,0]         (01)        (0)
                           split by x1
 [1,0] [0,1]      0        (0)   (1)
   0     1

我怎样才能从训练有素的决策树中得到这个(左计数)?

我可以看到一个c.tree_变量,但内容似乎不是很有帮助。有零,权重,......很难猜出如何取回计数。

每个 class 的样本数存储在 tree_.value 中,但是它只存储叶子的节点值,所以我使用 post-顺序遍历来获取所有节点的值.

import numpy as np

def get_value(dt):
    left = dt.tree_.children_left
    right = dt.tree_.children_right
    value = dt.tree_.value
    leaves = np.argwhere(left == -1)[:, 0]

    def visit(node):
        if node in leaves:
            return
        visit(left[node])
        visit(right[node])
        value[node, :] = value[left[node], :] + value[right[node], :]

    visit(0)
    return value

例如,

from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
dt.fit([[0,0],
        [0,1],
        [1,1]], [0,1,0])
get_value(dt)

输出:

[[[ 2.  1.]]

 [[ 1.  1.]]

 [[ 1.  0.]]

 [[ 0.  1.]]

 [[ 1.  0.]]]

更新#1

我想知道为什么tree_.value只存储叶节点的值,然后我找到了 and this issue

事实证明,在 scikit-learn 0.17.dev0 中,tree_.value 已经 returns 所有节点的值。

In [1]: from sklearn.tree import DecisionTreeClassifier

In [2]: dt = DecisionTreeClassifier()

In [3]: dt.fit([[0,0],
   ...:         [0,1],
   ...:         [1,1]], [0,1,0])
Out[3]:
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            max_features=None, max_leaf_nodes=None, min_samples_leaf=1,
            min_samples_split=2, min_weight_fraction_leaf=0.0,
            random_state=None, splitter='best')

In [4]: dt.tree_.value
Out[4]:
array([[[ 2.,  1.]],

       [[ 1.,  1.]],

       [[ 1.,  0.]],

       [[ 0.,  1.]],

       [[ 1.,  0.]]])

更新 #2

虽然我认为在给出 class_weight 对 "undo the weighting" 没有 有意义,但有可能实现。

class_weight

计算
In [1]: from sklearn.utils import compute_class_weight

In [2]: compute_class_weight('auto', [0, 1], [0, 1, 0])
Out[2]: array([ 0.66666667,  1.33333333])

所以可以在if node in leaves:后加上value[node, :] /= class_weight重新计算叶子节点的值