在R中将关系数据转换为分层列表

10
这是我的第一个问题,请温柔点。
我有一些数据,格式如下:
library('networkD3')
    Relationships<- data.frame(Parent=c("earth","earth","forest","forest","ocean","ocean","ocean","ocean"),
                  Child=c("ocean","forest","tree","sasquatch","fish","seaweed","mantis shrimp","sea monster"))
> Relationships
  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

基本上这是一个边缘列表,可以用来制作网络地图:
net <- graph_from_data_frame(d = Relationships,
                             directed = T)
plot(net)

enter image description here

我希望将其转换为一个可在下面的diagonalNetwork函数中使用的形式。
Hierarchical_list <- list(name = "earth",
                 children = list(list(name = "ocean",
                                      children = list(list(name = "mantis shrimp"),
                                                      list(name = "fish"),
                                                      list(name = "sea monster"),
                                                      list(name = "seaweed")
                                                      )),
                                 list(name = "forest",
                                      children = list(list(name = "sasquatch"),
                                                      list(name = "tree")
                                                      ))
                 ))
diagonalNetwork(Hierarchical_list)

像这样:

enter image description here

当我尝试使用以下循环生成列表时:
    List_attempt <- list()

levels<- levels(factor(Relationships$Parent))

for(n in 1:length(levels)){
  Children <- subset(Relationships, Relationships$Parent == levels[n], select = Child)
  for(c in 1:length(Children)){
    sublist <- as.list(Children)
    List_attempt <- list(List_attempt, name = levels[n],children = sublist)
  }
}

diagonalNetwork(List_attempt)

我得到了这个错误:

Error in FUN(X[[i]], ...) : 
  'options' must be a fully named list, or have no names (NULL)

1) 有没有更好的方法创建diagonalNetwork的列表?

2) 如果没有,我该如何修改循环以生成正确结构的列表?

3) 是否应该使用完全不同的函数/包?

感谢您提供的任何帮助,我已经为此问题苦恼了一段时间。欢迎提供关于在SO上提问更好的方式的反馈。

澄清:

类似的问题在这里找到,将数据框转换为treeNetwork兼容列表。但是它依赖于一个数据结构,其中根始终在第一列中,其子项在后续列中,而不是像本问题中那样的边列表,这在igraph中通常使用。


@Procrastinatus Maximus,我编辑了一下以澄清这两个问题之间的区别。那个问题有着相同的最终目标,但它并没有转换关系数据,它只适用于根节点在第一列且整个父子结构在随后的列中的情况,而这种情况在边缘列表中并不适用。 - Chris P
好的,我已经重新打开了这个问题。 - Jaap
2个回答

11

你可以使用data.tree包,它可以直接进行许多层次数据的转换:

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

library('data.tree')
tree <- FromDataFrameNetwork(Relationships)
tree
lol <- ToListExplicit(tree, unname = TRUE)
diagonalNetwork(lol)

1
感谢@Symbolix指出错误。
受到@MrFlick评论的启发,建议从根开始获取子元素来递归创建列表元素 :) ...... 当然还可以进一步改进以增强对意外数据输入的鲁棒性。
library(igraph)
library('networkD3')
Relationships<- data.frame(Parent=c("earth","earth","forest","forest","ocean","ocean","ocean","ocean"),
    Child=c("ocean","forest","tree","sasquatch","fish","seaweed","mantis shrimp","sea monster"))
net <- graph_from_data_frame(d=Relationships, directed=T)
plot(net)

#net and Relationships as declared in question
#get root
root <- setdiff(Relationships$Parent, Relationships$Child)

#traverse next layer and then recurve
as.list.igraph <- function(thisNode) {
    nm <- vertex_attr(net, "name", thisNode)
    childNodes <- V(net)[which(shortest.paths(net, thisNode, mode="out") == 1)]
    if (length(childNodes)==0) return(list(name=nm))
    list(name=nm, children=unname(lapply(childNodes, as.list.igraph)))
}

#plot D3 network
diagonalNetwork(as.list.igraph(V(net)[root]))

顺便提一句,如果我没记错的话,igraph中也有一个layout.reingold.tilford选项


这些返回的结构与问题中发布的不同。 - SymbolixAU
@Symbolix 很好的发现,这些结构是不同的,但只是顺序不同。对于我的目标(图形),这并不是一个问题。我将研究layout.reingold.tilford选项。 - Chris P
这将帮助很多,允许我使用 networkd3 包的一些特性,在一些我现在使用 igraph 绘图的东西上,避免重复性工作。谢谢。 - Chris P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接