将edgelist转换为data.tree

时间:2017-05-13 18:31:45

标签: r dataframe tree

我想使用R中的data.tree库将edgelist转换为树对象。

这是我的代码:

library(data.tree)

edges <- read.csv("data.csv")
colnames(edges) <- c("source", "target") 

R1 <- data.frame(Parent=edges$source, Child=edges$target)

R2<- data.frame(Parent=c("earth","earth","forest","forest","ocean","ocean","ocean","ocean"),
                           Child=c("ocean","forest","tree","sasquatch","fish","seaweed","mantis shrimp","sea monster"))

现在,如果我运行tree <- FromDataFrameNetwork(R2),事情就会发挥作用。但如果我tree <- FromDataFrameNetwork(R1),我会收到以下错误:

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?

这怎么可能?

R1看起来像这样:

  Parent Child
1      1     6
2      4     2
3      3     5
4      1     4
5      1     5
6      5     3

R2看起来像这样:

  Parent         Child
1  earth         ocean
2  earth        forest
3 forest          tree
4 forest     sasquatch
5  ocean          fish
6  ocean       seaweed
7  ocean mantis shrimp
8  ocean   sea monster

1 个答案:

答案 0 :(得分:0)

正如@lukeA所说,R1包含一个循环关系。如果3是5的父级,而5是3的父级,则FromDataFrameNetwork(R1)将在尝试构建树时无限递归。您可以编写一个递归帮助函数来验证要转换为树的表,例如:

library(tidyverse)

validate <- function(origin, tree, ancestors = character()){
  ancestors = c(ancestors, origin)

  kids <- tree %>%
    filter(Parent == origin) %>%
    select(Child) %>%
    pull()

  invalid.kids <- kids[kids %in% ancestors] # if any Child appears in its own ancestry, then it's invalid

  if(length(invalid.kids)){
    print(paste('invalid children:',
    paste(invalid.kids, collapse = ', '),
    'parent:',
    origin)) # print Children that produce circular relationships for debugging

  }

  children <- lapply(kids[!(kids %in% ancestors)], validate, tree, ancestors) # recursively apply validate() to all valid Children

  tree <- filter(tree, !(Child %in% invalid.kids)) # key step: filter out parts that would cause an infinite loop

  return(rbind(tree, do.call(rbind, children)))
}

警告:我还没有测试这个确切的脚本,但是过去我使用过类似的方法。