如何解释 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.2DecisionTreeClassifier 存根配置为:
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 属性的(意外)值?的主要内容,如果未能解决你的问题,请参考以下文章