如何使用路径爬上rpart对象的树结构以手动清除某些节点?

时间:2016-03-18 13:09:58

标签: r machine-learning rpart

我使用rpart构建分类树。我想根据叶节点上的一些标准开发自己的修剪功能。 例如,如果一个叶节点不符合某些标准(在我的情况下参数估计的稳定性),我想爬上树结构并获得该叶节点的父节点(即使该节点不是终端) 。 为此,我想使用路径遍历树,我需要使用父节点获取叶节点,以便在必要时爬树。

让我们看一下这个例子:

fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis)

> fit
n= 81 

node), split, n, loss, yval, (yprob)
 * denotes terminal node

1) root 81 17 absent (0.79012346 0.20987654) 
2) Start>=8.5 62 6 absent (0.90322581 0.09677419) 
4) Start>=14.5 29 0 absent (1.00000000 0.00000000) *
5) Start< 14.5 33 6 absent (0.81818182 0.18181818) 
10) Age< 55 12 0 absent (1.00000000 0.00000000) *
11) Age>=55 21 6 absent (0.71428571 0.28571429) 
22) Age>=111 14 2 absent (0.85714286 0.14285714) *
23) Age< 111 7 3 present (0.42857143 0.57142857) *
3) Start< 8.5 19 8 present (0.42105263 0.57894737) *

使用fit $ frame,我可以获得有关叶节点的信息:

fit$frame 

var n wt dev yval complexity ncompete nsurrogate yval2.V1 yval2.V2 yval2.V3 yval2.V4 yval2.V5
1 Start 81 81 17 1 0.17647059 2 1 1.00000000 64.00000000 17.00000000 0.79012346 0.20987654
2 Start 62 62 6 1 0.01960784 2 2 1.00000000 56.00000000 6.00000000 0.90322581 0.09677419
4 <leaf> 29 29 0 1 0.01000000 0 0 1.00000000 29.00000000 0.00000000 1.00000000 0.00000000
5 Age 33 33 6 1 0.01960784 2 2 1.00000000 27.00000000 6.00000000 0.81818182 0.18181818
10 <leaf> 12 12 0 1 0.01000000 0 0 1.00000000 12.00000000 0.00000000 1.00000000 0.00000000
11 Age 21 21 6 1 0.01960784 2 0 1.00000000 15.00000000 6.00000000 0.71428571 0.28571429
22 <leaf> 14 14 2 1 0.01000000 0 0 1.00000000 12.00000000 2.00000000 0.85714286 0.14285714
23 <leaf> 7 7 3 2 0.01000000 0 0 2.00000000 3.00000000 4.00000000 0.42857143 0.57142857
3 <leaf> 19 19 8 2 0.01000000 0 0 2.00000000 8.00000000 11.00000000 0.42105263 0.57894737

我可以使用相应的叶子节点获取数据表中行的对应关系:fit $ where

现在我想得到一个叶子节点的父节点。我知道path.rpart给了我完成的所有拆分以获取叶子节点。例如,对于叶节点23:

> path.rpart(fit, 23)

node number: 23 
 root
 Start>=8.5
 Start< 14.5
 Age>=55
 Age< 111

我想要获得的是具有节点23的父节点的节点号的路径?我该怎么做这个联想?

提前谢谢。

1 个答案:

答案 0 :(得分:2)

由于所有节点都具有相同的模式,因此您不需要有关树的任何信息。让我们选择一个更有趣的树:

(fit <- rpart(Kyphosis ~ Age + Number + Start, data = kyphosis,
             cp = .0001, minsplit = 5))

# n= 81 
# 
# node), split, n, loss, yval, (yprob)
#       * denotes terminal node
# 
#   1) root 81 17 absent (0.79012346 0.20987654)  
#     2) Start>=8.5 62  6 absent (0.90322581 0.09677419)  
#       4) Start>=14.5 29  0 absent (1.00000000 0.00000000) *
#       5) Start< 14.5 33  6 absent (0.81818182 0.18181818)  
#        10) Age< 55 12  0 absent (1.00000000 0.00000000) *
#        11) Age>=55 21  6 absent (0.71428571 0.28571429)  
#          22) Age>=98 16  2 absent (0.87500000 0.12500000) *
#          23) Age< 98 5  1 present (0.20000000 0.80000000) *
#     3) Start< 8.5 19  8 present (0.42105263 0.57894737)  
#       6) Age< 11.5 2  0 absent (1.00000000 0.00000000) *
#       7) Age>=11.5 17  6 present (0.35294118 0.64705882)  
#        14) Start< 5.5 12  6 absent (0.50000000 0.50000000)  
#          28) Age>=130.5 2  0 absent (1.00000000 0.00000000) *
#          29) Age< 130.5 10  4 present (0.40000000 0.60000000)  
#            58) Age< 93 6  2 absent (0.66666667 0.33333333)  
#             116) Number< 4.5 3  0 absent (1.00000000 0.00000000) *
#             117) Number>=4.5 3  1 present (0.33333333 0.66666667) *
#            59) Age>=93 4  0 present (0.00000000 1.00000000) *
#        15) Start>=5.5 5  0 present (0.00000000 1.00000000) *

如果可能,每个节点将被拆分为两个并编号为node * 2 + 0:1,因此如果您有一个编号为5的节点,其子节点将为5 * 2 + 0:1。另请注意,使用此模式时,偶数编号的节点都不会有子节点。

因此,给定任何节点编号,我们可以回过头来找到父母:

parent(23)
# [1]  1  2  5 11 23

## children of the same node should have the same path
identical(head(parent(28), -1), head(parent(29), -1))
# [1] TRUE

parent <- function(x) {
  if (x[1] != 1)
    c(Recall(if (x %% 2 == 0L) x / 2 else (x - 1) / 2), x) else x
}