我有一个树结构,具有唯一标识的节点,根和一堆分支。对任何节点可以萌芽的分支数量或者它们可以进行多深的分支没有限制。
我想做的是,给定节点的id,有效地返回该节点的所有父节点的id,以及每个父节点的所有兄弟节点。我希望这个特定问题的答案将使用为此类操作设计的包/函数,以便我可以了解它们并将它们用于将来的类似问题,而不是每次都必须编写自定义算法。
这是以父母形式的树:
structure(list(child = 1:20, parent = c(NA, 1L, 2L, 3L, 1L, 5L, 6L, 5L, 8L, 1L, 1L, 11L, 12L, 11L, 14L, 14L, 1L, 17L, 18L, 19L)), .Names = c("child", "parent"), class = "data.frame", row.names = c(NA, -20L))
这是一个直观的表示:
对于特定问题,我的目标id是13(红色),并且想获得父节点的id(橙色),以及父节点的兄弟节点(黄色)。我绝对可以想出一个算法来做到这一点(让所有的父母都很容易,然后兄弟姐妹意味着让每个父母的父母的孩子),但我真的希望已经有一个框架来做所有这很有效。
我简要介绍了rpart
,tree
和ape
,但据我简要回顾一下,他们的目标是对树木进行统计分类,而不是操纵/检索树木。节点,在我看来,基于一些有点敷衍的评论,他们没有提供我之后的功能(完全可能是我错过了它/误解了它)。
另一个选项似乎是XML
或xmlTree
,它允许我使用一些DOM操作工具来实现我的目标,但它似乎有点沉重,也许不是最优的。
答案 0 :(得分:2)
我已经多次发现自己处于类似情况,而且我通常只是推出自己的解决方案。我同意XML包对于诸如此类的重点问题而言过于苛刻。 iGraph包很不错,但要注意。它是C库的接口,并且是零索引的(与1索引的R不同)。我成功地使用了它,但似乎总是有一个痛苦的调试过程,我不断发现"未移位"索引。 (例如foo[index]
必须更改为foo[index-1]
。)
同样,我可能只是自己动手。类似的东西:
foo <- structure(list(child = 1:20, parent = c(NA, 1L, 2L, 3L, 1L, 5L, 6L, 5L, 8L, 1L, 1L, 11L, 12L, 11L, 14L, 14L, 1L, 17L, 18L, 19L)), .Names = c("child", "parent"), class = "data.frame", row.names = c(NA, -20L))
get_ancestry <- function(node, data=foo, ancestry=c()) {
parent <- data$parent[data$child %in% node]
if (is.na(parent)) {
return(ancestry)
} else {
get_ancestry(parent, data, c(ancestry, parent))
}
}
get_children <- function(nodes, data=foo) {
unlist(lapply(nodes, function(x) {data$child[data$parent %in% x]}))
}
orange <- get_ancestry(13)
yellow <- get_children(orange)
答案 1 :(得分:1)
感谢指点,igraph
绝对是我正在寻找的,虽然我有点超出我的深度。在python igraph
tutorial的帮助下,我得到了:
g <- graph(t(as.matrix(df[-1, 2:1]))) # Make graph
plot(g) # yes, this matches mine
parents <- unlist( # orange nodes
neighborhood(
g,
order=ecount(g), # how many steps to go up, this should guarantee we get to root
nodes=13, # starting point
mode="in" # head in towards root
)
)[-1L]
setdiff( # yellow nodes
unique(
unlist(
lapply(parents, neighborhood, graph=g, order=1, mode="out")
) ),
c(parents, 13)
)
产生所需的答案。不幸的是,由于neighborhood
函数的返回格式,每一步都需要进行一些后处理。