我使用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的父节点的节点号的路径?我该怎么做这个联想?
提前谢谢。
答案 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
}