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

Posted

技术标签:

【中文标题】如何解释 sklearn.tree.tree_tree.value 属性的(意外)值?【英文标题】:How to interpret (unexpected) values of sklearn.tree.tree_tree.value attribute? 【发布时间】:2019-06-05 15:47:19 【问题描述】:

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

版本信息

蟒蛇:3.6.5 sklearn 版本:0.20.2

DecisionTreeClassifier 存根配置为:

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

AdaBoostClassifier 是一个二元分类器,输出状态为 Class A 和 Class B(编码为 +1 和 -1)。训练集由 23 个特征组成,分类器执行良好(预测准确率、精度、召回率均约为 79%)。我正在分析错过的预测,以深入了解分类错误。

有 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 属性是每个类中的样本数而不是百分比。但在根节点中,0.5 值确实反映了我拥有的平衡训练集,两个类的表示相同。

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

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

这些价​​值量代表什么?

考虑到左叶节点,我的数据集实际上有 264 个 delta_win_pct

同样,对于右子节点,值数据提供为 [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,表明左侧节点具有大多数 A 类样本。而在右叶节点中,当 delta_win_pct > 阈值时,0.207

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

【问题讨论】:

【参考方案1】:

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

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)

我发现有两种情况,一种是“正确的”(clf.estimators_[0]),一种看起来像这样

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

如果您将proportion 参数设置为True,您将获得每个节点的类分布百分比,例如对于节点#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])是您遇到的情况:

左节点类:[74, 7]

Rignt 节点类:[93, 26]

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

>>> 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.]]])

【讨论】:

感谢您抽出宝贵时间进行调查。我可以使用我的数据确认您的发现。 AdaBoostClassifier 返回的估计器列表中的第一个估计器包含一个值属性,其值对应于根节点中标识的总样本/观察的百分比。列表中的其他剩余估计器都没有与此约定匹配的值属性。我还怀疑您是正确的,鉴于您单独提供的树数据的证明,值属性的值受 AdaBoostClassifier 算法(不知何故)影响。 我将暂时搁置这个问题,也许有人可以更深入地了解在提升时如何计算估计量的值。我将跟随您的领导并查看源代码。我会报告任何发现。 接受了地狱般的回答。【参考方案2】:

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

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。【参考方案3】:

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

【讨论】:

以上是关于如何解释 sklearn.tree.tree_tree.value 属性的(意外)值?的主要内容,如果未能解决你的问题,请参考以下文章

将 json 解释为字符串,如何将其解释为 json? [复制]

代码案例详解!如何让机器学习模型自解释!⛵

如何解释 TensorFlow 输出?

如何解释 LDA 组件(使用 sklearn)?

JAVA 里面如何 使用jni 给个例子 加 解释。谢谢

scikit-learn RandomForestClassifier - 如何解释树输出?