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

How to climb the tree structure of rpart object using path in order to purge manually some nodes?

我正在使用 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

我可以得到数据中行的对应关系 table 使用它所在的相应叶节点:fit$where

现在我还想获得叶节点的父节点。我知道 path.rpart 为我提供了为获得叶节点而完成的所有拆分。例如对于叶节点 23:

> path.rpart(fit, 23)

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

我要获取的是23号节点的父节点号的路径?我怎样才能做这个关联?

提前致谢。

您不需要关于树的任何信息,因为所有节点都具有相同的模式。让我们拟合一棵更有趣的树:

(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
}