决策树会根据某些中断条件拆分节点,并使用节点中值的平均值作为预测结果。
我想获取此类节点中的所有值,而不仅仅是平均值,以便进行更复杂的操作。我使用的是sklearn。我没有找到相关的答案,仅找到了使用DecisionTreeRegressor.tree_.value
获取所有节点平均值的方法。
如何做到这一点呢?
回答:
据我所知,没有任何API方法可以做到这一点,但你可以通过编程方式获取这些值。
让我们先创建一些虚拟数据并构建一个回归树来演示这一点:
import numpy as npfrom sklearn.tree import DecisionTreeRegressor, export_graphviz# 虚拟数据rng = np.random.RandomState(1) # 为了可重复性X = np.sort(5 * rng.rand(80, 1), axis=0)y = np.sin(X).ravel()y[::5] += 3 * (0.5 - rng.rand(16))estimator = DecisionTreeRegressor(max_depth=3)estimator.fit(X, y)import graphviz dot_data = export_graphviz(estimator, out_file=None) graph = graphviz.Source(dot_data) graph
这是我们决策树的图示:
从图中可以明显看出我们有8个叶子节点,每个节点的样本数量和平均值都被显示出来。
这里的关键命令是apply
:
on_leaf = estimator.apply(X)on_leaf# 结果:array([ 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14])
on_leaf
的长度等于我们的数据X
和结果y
;它给出了每个样本最终所在节点的索引(on_leaf
中的所有节点都是终端节点,即叶子节点)。其唯一值的数量等于我们的叶子节点数量,这里是8:
len(np.unique(on_leaf))# 8
并且on_leaf[k]
给出了y[k]
最终所在的节点号。
现在我们可以获取8个叶子节点中每个节点的实际y
值,如下所示:
leaves = []for i in np.unique(on_leaf): leaves.append(y[np.argwhere(on_leaf==i)]) len(leaves)# 8
让我们验证一下,根据我们的图示,第一个叶子节点只有一个样本,值为-1.149
(由于它是单样本叶子节点,样本的值等于平均值):
leaves[0]# array([[-1.1493464]])
看起来不错。第二个叶子节点呢,有10个样本,平均值为-0.173
?
leaves[1]# 结果:array([[ 0.09131401], [ 0.09668352], [ 0.13651039], [ 0.19403525], [-0.12383814], [ 0.26365828], [ 0.41252216], [ 0.44546446], [ 0.47215529], [-0.26319138]])len(leaves[1])# 10leaves[1].mean()# 0.17253138570808904
依此类推 – 最后检查最后一个叶子节点(#7),有4个样本,平均值为-0.99
:
leaves[7]# 结果:array([[-0.99994398], [-0.99703245], [-0.99170146], [-0.9732277 ]])leaves[7].mean()# -0.9904763973694366
总结:
对于数据X
、结果y
和决策树回归器estimator
,你需要做的是:
on_leaf = estimator.apply(X)leaves = []for i in np.unique(on_leaf): leaves.append(y[np.argwhere(on_leaf==i)])