如何解释 sklearn.tree.tree_tree.value 属性的(意外)值?

How to interpret (unexpected) values of sklearn.tree.tree_tree.value attribute?

与 AdaBoostClassifier 一起使用的决策树 classifier 存根对应的 value 属性值与预期不符,我无法确定这些值表示什么。我想了解有助于分析存根估计器行为的值以及存根对 AdaBoostClassifier 的贡献。与 Whosebug 类似的问题与我的数据无关。

版本信息

DecisionTreeClassifier 存根配置为:

number_estimators = 301
bdt= AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), 
algorithm="SAMME.R", n_estimators=number_estimators)

AdaBoostClassifier 是一个二进制 classifier,输出状态为 Class A 和 Class B(编码为 +1 和 -1)。训练集包含 23 个特征,classifier 表现良好(预测准确度、精确度、召回率均约为 79%)。我正在分析错过的预测,以深入了解 class 化错误。

有782个训练样本。 301 个存根估计器是通过以下方式从 AdaBoostClassifier 获得的:

tree_stubs = bdt.estimators_

对应于第 6 个估计器(基于 0 的列表)的示例存根:

bdt.estimators_[5]
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=1,
        max_features=None, max_leaf_nodes=None,
        min_impurity_decrease=0.0, min_impurity_split=None,
        min_samples_leaf=1, min_samples_split=2,
        min_weight_fraction_leaf=0.0, presort=False,
        random_state=421257592, splitter='best')

此存根的值:

stub_5.tree_.value
array([[[0.5       , 0.5       ]],
   [[0.29308331, 0.1861591 ]],
   [[0.20691669, 0.3138409 ]]])       

对于那些熟悉 graphviz 的人来说,树桩看起来像:

根节点正确显示样本数 (782)。 value 属性表示 [0.5, 0.5]。我期望 value 属性是每个 class 中的样本数而不是百分比。但是在根节点中,0.5 值确实反映了我拥有的平衡训练集,两个 classes.

具有相同的表示

问题来了。此存根中的拆分功能根据 delta_win_pct 值小于或等于阈值 -.001 来划分样本。我的数据集确实有 385 个 delta_win_pct 小于此阈值的样本记录和 397 个 delta_win_pct 大于阈值的样本。所以samples数据在树桩的左右叶节点都是正确的。

但值数据似乎不正确。在左子节点中,值报告为值=[0.293, 0.186],在右子节点中,值=[0.207, 0.314]。请注意,这是 sklearn.tree._tee.Tree class 报告的数据,并不表示 graphviz 有任何问题。

这些数值量代表什么?

考虑到左叶节点,我的数据集实际上有 264 Class 个 A 样本,其 delta_win_pct <= -0.001 和 121 Class B 样本匹配此分裂阈值。这些数字对应于 [.6857, .3143] 而非 [0.293, 0.186] 的百分比。不正确的值不会线性缩放到预期值。

类似地,对于右子节点,值数据提供为 [0.207, 0.314],但对于 delta_win_pct 超过阈值的 397 个样本,预期值应为 [.330, .670]。

我注意到提供的数值数据(0.293、0.186、0.207、0.314)中的数字加起来为 1.0。但是每个节点的值加起来不等于 1.0。我尝试使用提供的值作为所有样本的百分比,例如0.293 * 782 = 229 与任何东西都不相关。

有人了解提供的价值数据的含义吗?我对这些值的解释和期望不正确吗?

最后,我注意到数据中值的相对大小与每个节点中的多数样本正确相关。左子节点中0.293大于0.186说明左节点拥有Class个样本的多数。而在右叶节点中 0.207 < 0.314 表示当 delta_win_pct > 阈值时大多数 Class B 样本。我怀疑这就是 AdaBoostClassifier 似乎正常工作的原因。

无论如何,我想了解这些价值。

我尝试在生成的数据集上重现它:

import pydot 
import numpy as np
from IPython.display import Image, display
from sklearn.externals.six import StringIO  
from sklearn.tree import DecisionTreeClassifier,  _tree
from sklearn.datasets import make_classification
from sklearn.ensemble import AdaBoostClassifier


X, y = make_classification(n_informative=2, n_features=3, n_samples=200, n_redundant=1, random_state=42, n_classes=2)
feature_names = ['X0','X1','X2','X3']
clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), 
algorithm="SAMME.R", n_estimators=301)
clf.fit(X, y)

estimator = clf.estimators_[0]
dot_data = StringIO() 
tree.export_graphviz(estimator, out_file=dot_data, proportion=False, filled=True,node_ids=True,rounded=True,class_names=['0','1']) 
graph = pydot.graph_from_dot_data(dot_data.getvalue()) [0]

def viewPydot(pdot):
    plt = Image(pdot.create_png())
    display(plt)
viewPydot(graph)

我发现有两种情况,一种是"proper" (clf.estimators_[0]),一种是这样的

这里value代表节点中某个特定的class占样本总数的比例,所以node#1:[84/200=0.42,7/200=0.035],node#2:[16/200=0.08,93/200=0.465]

如果您将 proportion 参数设置为 True,您将获得每个节点的 class 分布百分比,例如对于节点#2:[16/109, 93/109]=[0.147, 0.853]calculated using weighted_n_node_samples 属性在适当的情况下等于节点的样本数除以样本总数,例如109/200=0.545, [0.08, 0.465]/0.545=[0.147, 0.853]

另一种情况(clf.estimators_[4])是您遇到的情况:

左节点classes:[74, 7]

右节点 classes: [93, 26]

Class这里的分布与value不相关,左节点甚至预测少数class。 唯一合适的情况似乎是第一个估计器,其他人也有这个问题,也许这是提升程序的一部分?此外,如果您采用任何估算器树并手动进行拟合,您将获得与第一个估算器相同的数字,例如

>>> DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=1,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False,
            random_state=441365315, splitter='best').fit(X,y).tree_.value
array([[[100., 100.]],

       [[ 84.,   7.]],

       [[ 16.,  93.]]])

值数组以某种方式表示不是平衡问题时的预期结果。当模型参数未设置为 class_weight = 'Balanced' 时,这些值给出该节点内 class A 和 class B 的比例;但是当模型参数设置为 class_weight = 'Balanced' 时,这些值会给出意外的输出。

在 AdaBoost 中,每个数据点都被分配了一个权重。最初,所有权重都相等(1/样本总数)。在 AdaBoost 中,树是按顺序训练的。在我们训练第一棵树之后,每个数据点的权重都会根据第一棵树所犯的错误进行调整。所以,当我们开始训练第二棵树时,数据点的权重是不同的。因此,在这种情况下,值表示每个 class.

的数据点的权重总和