在分层 data.frame 中查找根节点

Find root nodes in a hierarchical data.frame

提问人:ahnungslos 提问时间:10/12/2021 更新时间:10/12/2021 访问量:135

问:

我有一个为我提供其行()的分层信息:data.frameDF_in

   id parent_id
1   1        NA
2   2        NA
3   3         1
4   4         2
5   5         3
6   6         4
7   7         1
8   8         2
9   9         3
10 10         4

我想找到每行的root_id():DF_out

   id parent_id root_id
1   1        NA      NA
2   2        NA      NA
3   3         1       1
4   4         2       2
5   5         3       1
6   6         4       2
7   7         1       1
8   8         2       2
9   9         3       1
10 10         4       2

通常我更喜欢使用 ,但这似乎需要一个递归解决方案,我不知道如何有效地解决这个问题。data.table

DF_in <- data.frame(id = 1:10, parent_id = c(NA, NA, 1:4, 1:4))
# library(data.table)
# setDT(DF_in)

DF_out <- data.frame(id = 1:10, parent_id = c(NA, NA, 1:4, 1:4), root_id = c(NA, NA, rep(1:2, 4)))
r 数据表

评论

0赞 Cath 10/12/2021
您可能应该看看软件包 iGraph
1赞 ahnungslos 10/12/2021
谢谢你的提示!你有什么具体的功能吗?

答:

1赞 s_baldur 10/12/2021 #1

快速点:

find_root <- function(id, table) {
  par <- table[match(id, table$id), 'parent_id']
  if (is.na(par)) id else find_root(id = par, table)
}

DF_in$root_id <- vapply(DF_in$id, \(x) find_root(x, DF_in), integer(1L))


> DF_in
   id parent_id root_id
1   1        NA       1
2   2        NA       2
3   3         1       1
4   4         2       2
5   5         3       1
6   6         4       2
7   7         1       1
8   8         2       2
9   9         3       1
10 10         4       2
1赞 Mischa 10/12/2021 #2

这是使用 .当然,如果需要多次运行这段代码,您可以将其转换为函数。dplyr

library(dplyr)
#> 
#> Attache Paket: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

id <- c(1:10)

parent_id <- c(NA, NA, 1, 2, 3, 4, 1, 2, 3, 4)

df <- tibble(id = id, parent_id = parent_id)

df %>%
  mutate(
    root_id = pull(
      left_join(
        x = df,
        y = df,
        by = c("parent_id" = "id")),
      "parent_id.y"),
    root_id = ifelse(
      test = is.na(root_id) & !is.na(parent_id),
      yes = parent_id,
      no = root_id
    )
  )
#> # A tibble: 10 x 3
#>       id parent_id root_id
#>    <int>     <dbl>   <dbl>
#>  1     1        NA      NA
#>  2     2        NA      NA
#>  3     3         1       1
#>  4     4         2       2
#>  5     5         3       1
#>  6     6         4       2
#>  7     7         1       1
#>  8     8         2       2
#>  9     9         3       1
#> 10    10         4       2

创建于 2021-10-12 由 reprex 软件包 (v2.0.1)