将数据框转换为列表的树结构列表 [英] Transform a dataframe into a tree structure list of lists

查看:184
本文介绍了将数据框转换为列表的树结构列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据框架,两列表示层次结构,父级和节点。



我想以一种我可以使用的方式来转换其结构作为 d3tree 的功能的输入,来自 d3Network 包。



这是我的数据框架:

  df<  -  data.frame(c(Canada,Canada 魁北克省,安大略省,安大略省),c(魁北克省,安大略省,蒙特利尔,魁北克市,多伦多,渥太华 (df)<  -  c(parent,child)

而且我想转换这个结构

  Canada_tree<  -  list(name =Canada,children = list(
list name =Quebec,
children = list(list(name =Montreal),list(name =Quebec City))),
list(name =Ontario,
children = list(list(name =Toronto),list(name =Ot tawa)))))

我已经使用以下代码成功地转换了这种特殊情况: p>

  fill_list<  -  function(df,node)node<  -  as.character(node)if(is.leaf(df, node)== TRUE){
return(list(name = node))
}
else {
new_node = df [df [,1] == node,2]

return(list(name = node,children = list(fill_list(df,new_node [1]),fill_list(df,new_node [2]))))
}

问题是,它只适用于每个父节点正好两个孩子的树。
您可以看到我将两个孩子(new_node [1]和new_node [2])硬编码为我的递归函数的输入。



我正在尝试找出一种我可以像父节点子节点一样调用递归函数的方式。
示例:

  fill_list(df,new_node [1]),...,fill_list(df,new_node [长度(new_node)])

我尝试了这3种可能性,但没有任何工作:



首先:创建一个包含所有函数和参数的字符串,然后进行评估。它返回这个错误找不到函数fill_functional(df,new_node [1])。这是因为我的功能毕竟是没有创建的。

  fill_functional<  -  function(df,node ){
node < - as.character(node)
if(is.leaf(df,node)== TRUE){
return(list(name = node))
}
else {
new_node = df [df [,1] == node,2]
level< - length(new_node)
xxx< - paste0 (df,new_node [,seq(level),]))
lapply(xxx,function(x)eval(call(paste(fill_functional,x,sep =

}
}

第二:强>使用for循环。但是我只收到了我的根节点的孩子。

  L<  -  list()
fill_list&函数(df,node){
node < - as.character(node)
if(is.leaf(df,node)== TRUE){
return(list(name =节点))
}
else {
new_node = df [df [,1] == node,2]

for(i in 1:length(new_node )){
L [i]< - (fill_list(df,new_node [i]))
}

return(list(name = node,children = L) )
}
}

第三:创建一个函数,它使用作为函数的元素填充列表,并且只是更改参数。但是我无法做任何有趣的事情,恐怕我会遇到同样的问题,就像我上面第一次尝试一样。

解决方案

这是递归定义:

  maketreelist<  -  function(df,root = df [ 1,1]){
if(is.factor(root))根< - as.character(root)
r< - list(name = root)
children = df [ df [,1] == root,2]
if(is.factor(children))children< - as.character(children)
if(length(children)> 0){
r $ children< - lapply(children,maketreelist,df = df)
}
r
}

canadalist< - maketreelist(df)

这会产生你想要的东西。此函数假定您传入的 data.frame (或 matrix )的第一列包含 parent 列,第二列有。它还需要一个参数,它允许您指定起点。它将默认为列表中的第一个父项。



但是,如果你真的有兴趣玩树。 igraph 包可能是有意义的

 库(igraph)
g< - graph.data.frame(df)
plot(g)


I have a data.frame with two columns representing a hierarchical tree, with parents and nodes.

I want to transform its structure in a way that I can use as an input for the function d3tree, from d3Network package.

Here's my data frame:

df <- data.frame(c("Canada","Canada","Quebec","Quebec","Ontario","Ontario"),c("Quebec","Ontario","Montreal","Quebec City","Toronto","Ottawa"))
names(df) <- c("parent","child")

And I want to transform it to this structure

Canada_tree <- list(name = "Canada", children = list(
                                                list(name = "Quebec", 
                children = list(list(name = "Montreal"),list(name = "Quebec City"))),
                                                 list(name = "Ontario", 
                children = list(list(name = "Toronto"),list(name = "Ottawa")))))

I have succesfully transformed this particular case using this code below:

fill_list <- function(df,node) node <- as.character(node)if (is.leaf(df,node)==TRUE){
    return (list(name = node))
  }
  else {
    new_node = df[df[,1] == node,2]

    return (list(name = node, children =  list(fill_list(df,new_node[1]),fill_list(df,new_node[2]))))
  }

The problem is, it only works with trees which every parent node has exactly two children. You can see I hard coded the two children (new_node[1] and new_node[2]) as inputs for my recursive function.

I'm trying to figure out a way that I could call the recursive function as many time as the parent's node children. Example:

fill_list(df,new_node[1]),...,fill_list(df,new_node[length(new_node)])

I tried these 3 possibilities but none of it worked:

First: Creating a string with all the functions and parameters and then evaluating. It return this error could not find function fill_functional(df,new_node[1]). That's because my function wasn´t created by the time I called it after all.

fill_functional <- function(df,node) {
  node <- as.character(node)
  if (is.leaf(df,node)==TRUE){
    return (list(name = node))
  }
  else {
    new_node = df[df[,1] == node,2]
    level <- length(new_node)
    xxx <- paste0("(df,new_node[",seq(level),"])")
    lapply(xxx,function(x) eval(call(paste("fill_functional",x,sep=""))))

  }
}

Second: Using a for loop. But I only got the children of my root node.

L <- list()
fill_list <- function(df,node) {
  node <- as.character(node)
  if (is.leaf(df,node)==TRUE){
    return (list(name = node))
  }
  else {
    new_node = df[df[,1] == node,2]

    for (i in 1:length(new_node)){
      L[i] <- (fill_list(df,new_node[i]))
    }

    return (list(name = node, children = L))
  }
}

Third: Creating a function that populates a list with elements that are functions, and just changing the arguments. But I wasn't able to accomplish anything interesting, and I'm afraid I'll have the same problem as I did on my first try described above.

解决方案

Here is a recursive definition:

maketreelist <- function(df, root = df[1, 1]) {
  if(is.factor(root)) root <- as.character(root)
  r <- list(name = root)
  children = df[df[, 1] == root, 2]
  if(is.factor(children)) children <- as.character(children)
  if(length(children) > 0) {
    r$children <- lapply(children, maketreelist, df = df)
    }
  r
  }

canadalist <- maketreelist(df)

That produces what you desire. This function assumes that the first column of the data.frame (or matrix) you pass in contains the parent column and the second column has the child. it also takes a root parameter which allows you to specify a starting points. It will default to the first parent in the list.

But if you really are interested in playing round with trees. The igraph package might be of interest

library(igraph)
g <- graph.data.frame(df)
plot(g)

这篇关于将数据框转换为列表的树结构列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆