【问题标题】:Function to find sub ID's of an ID in a data frame在数据框中查找 ID 的子 ID 的函数
【发布时间】:2023-03-11 19:46:01
【问题描述】:

我有一个包含两列的数据框,一个 ID 列和一个带有与相应 ID 相关的子 ID 的列。子 ID 可以再次具有子 ID(在这种情况下,以前的子 ID 现在是一个 ID)。

library(tibble)

df <- tibble(id = c(1, 1, 2, 2, 3, 7), sub_id = c(2, 3, 4, 5, 6, 8))

df

# A tibble: 6 x 2
     id sub_id
  <dbl>  <dbl>
1     1      2
2     1      3
3     2      4
4     2      5
5     3      6
6     7      8

我想编写一个函数来查找与 ID 相关的所有子 ID。它应该返回一个包含所有子 ID 的向量。

find_all_sub_ids <- function (data, id) {
data %>% ...
}

find_all_sub_ids(df, id = 1)

[1] 2 3 4 5 6

find_all_sub_ids(df, id = 2)

[1] 4 5

find_all_sub_ids(df, id = 9)

[1] NULL

这与我迄今为止在 R 中所做的一切都非常不同,我很难为这个问题写一个好的标题。因此,如果使用正确的措辞,我可能已经通过谷歌搜索找到了答案。

我解决这个问题的第一个直觉是 while 循环。由于我也不知道可能有多少子级别,因此该功能应继续执行,直到找到所有子级别。虽然我从来没有使用过 while 循环,也不知道如何在这里实现它们。

也许有人知道解决这个问题的好方法。谢谢!

编辑:忘记将 tibble 分配给 df 并在函数调用中使用此参数。

【问题讨论】:

  • 如果只有2,3,为什么find_all_sub_ids(id = 1) 会给你这么多数字?
  • dplyr 和你的tibble 叫DF 你可以做find_all_sub_ids &lt;- function (x) dplyr::filter(DF, id==x) %&gt;% .$sub_id

标签: r subset igraph tidygraph


【解决方案1】:

igraph:

library(igraph)
g <- graph_from_data_frame(d, directed = TRUE)

find_all_subs <- function(g,id){
  #find child nodes, first one being origin
  r <- igraph::subcomponent(g,match(id, V(g)$name),"out")$name
  #remove origin
  as.numeric(r[-1])
}
find_all_subs(g,1)
[1] 2 3 4 5 6

find_all_subs(g,2)
[1] 5 6

【讨论】:

  • 在使用我的实际数据进行尝试后,我注意到如果我使用不同的 ID,它就无法正常工作。 df &lt;- tibble(id = c(10, 10, 20, 20, 30, 40, 50, 60, 70), sub_id = c(200, 300, 400, 500, 600, 700, 800, 900, 1000)) 如果您查找 id = 10,则不会得到 200 和 300。r 将返回 400 但随后为 NULL,因为 r[-1]。
  • 查看我的编辑,又是 id vs name 问题,这次是函数的 id 输入。 igraph 仍然是一个很好的解决方案,但必须控制 id/name 逻辑;)
  • 我觉得你可以用subcomponent(g,toString(id),"out")$name来解决问题
  • @ThomasIsCoding,我尝试了您的建议,但收到“无效顶点名称”错误。请参阅我的编辑:有点棘手。然而,这是 igraph 包的创建者的suggested way
  • 我认为 OP 想要 id = 10 的结果 find_all_subs(g,10),因此您可以使用字符 "10" 作为输入
【解决方案2】:

我认为将其表述为图形问题是最简单的方法。
您的 data.frame 描述了一个有向图(从 id 到 sub_id 的顶点),并且您对从某个顶点可到达哪些节点感兴趣。

使用tidygraph,可以这样实现:

library(tidyverse)
library(tidygraph)

df <- tibble(id = c(1, 1, 2, 2, 3, 7), sub_id = c(2, 3, 4, 5, 6, 8))

find_all_sub_ids <- function (id) {
  if (!(id %in% df$id)) {
    return(NULL)
  }

  
  grph <- df %>% 
    as_tbl_graph(directed = TRUE)
  
  id <- which(grph %>% pull(name) == as.character(id))
  
  grph %>% 
    activate(nodes) %>% 
    mutate(reachable = !is.na(bfs_dist(id))) %>% 
    as_tibble() %>% 
    filter(reachable) %>% 
    pull(name) %>% 
    as.numeric()
}

我们查看哪些节点是可到达的(它们与您的给定节点有非 NA 距离),我们使用bfs_dist(请参阅here 以获得解释)。
这给了

> find_all_sub_ids(1)
[1] 1 2 3 4 5 6

> find_all_sub_ids(2)
[1] 2 4 5

> find_all_sub_ids(9)
NULL

这种方法的优点是它可以搜索很多层次,而无需显式编写循环。

编辑 我的代码中有一个错误,tidygraph::bfs_dist 使用的 id 与我预期的不同。现在修复它。
关于新示例:

> find_all_sub_ids(10)
[1]  10 200 300

【讨论】:

  • 感谢您的回答!这运作良好,并做了它应该做的。感谢您的解释,我在这里学到了一些新东西。
  • 另外在这里我注意到当我用我的实际数据测试它时它不能正常工作。 ``` df
  • 你是完全正确的 - 我的代码中有一个 ID 值的错误(它指的是行号而不是 ID 列的值)。请参阅编辑以获取工作示例。
【解决方案3】:

我是使用数据框完成的。以下工作。

x= c(1,1,2,2,3,7)
y = c(2, 3, 4, 5, 6, 8)
df <- data.frame(cbind(x,y))
colnames(df) =c('id', 'sub_id')


find_all_sub_ids <- function (df, id_requested) {
  si <- df[df$id==id_requested,]$sub_id
  return(si)
}
find_all_sub_ids(df,id=2)
[1] 4 5

【讨论】:

  • 感谢您的回答。但这与之前的答案相同。这个功能并没有做我所要求的。我想获取我的 ID 的所有子 ID。这个只给出直接子 ID 而不是他们的子 ID。 1 的子 ID 为 2(具有子 ID 4 和 5)和 3(具有子 ID 6)
猜你喜欢
  • 1970-01-01
  • 2020-03-05
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 2022-09-27
相关资源
最近更新 更多