2014-02-05 49 views
0

我想在R中创建一个与D3树结构flare.json对应的不齐列表。我的数据是在data.frame:Ragged list or data frame to JSON

path <- data.frame(P1=c("direct","direct","organic","direct"), 
P2=c("direct","direct","end","end"), 
P3=c("direct","organic","",""), 
P4=c("end","end","",""), size=c(5,12,23,45)) 

path 
     P1  P2  P3 P4 size 
1 direct direct direct end 5 
2 direct direct organic end 12 
3 organic end    23 
4 direct end    45 

,但它也可能是一个列表,或者如果有必要重塑:

path <- list() 
path[[1]] <- list(name=c("direct","direct","direct","end"),size=5) 
path[[2]] <- list(name=c("direct","direct","organic","end"), size=12) 
path[[3]] <- list(name=c("organic", "end"), size=23) 
path[[4]] <- list(name=c("direct", "end"), size=45) 

所需的输出是:

rl <- list() 
rl <- list(name="root", children=list()) 
rl$children[1] <- list(list(name="direct", children=list())) 
rl$children[[1]]$children[1] <- list(list(name="direct", children=list())) 
rl$children[[1]]$children[[1]]$children[1] <- list(list(name="direct", children=list())) 
rl$children[[1]]$children[[1]]$children[[1]]$children[1] <- list(list(name="end", size=5)) 

rl$children[[1]]$children[[1]]$children[2] <- list(list(name="organic", children=list())) 
rl$children[[1]]$children[[1]]$children[[2]]$children[1] <- list(list(name="end", size=12)) 

rl$children[[1]]$children[2] <- list(list(name="end", size=23)) 

rl$children[2] = list(list(name="organic", children=list())) 
rl$children[[2]]$children[1] <- list(list(name="end", size=45)) 

所以,当我打印到JSON它是:

require(RJSONIO) 
cat(toJSON(rl, pretty=T)) 

{ 
"name" : "root", 
"children" : [ 
    { 
     "name" : "direct", 
     "children" : [ 
      { 
       "name" : "direct", 
       "children" : [ 
        { 
         "name" : "direct", 
         "children" : [ 
          { 
           "name" : "end", 
           "size" : 5 
          } 
         ] 
        }, 
        { 
         "name" : "organic", 
         "children" : [ 
          { 
           "name" : "end", 
           "size" : 12 
          } 
         ] 
        } 
       ] 
      }, 
      { 
       "name" : "end", 
       "size" : 23 
      } 
     ] 
    }, 
    { 
     "name" : "organic", 
     "children" : [ 
      { 
       "name" : "end", 
       "size" : 45 
      } 
     ] 
    } 
] 
} 

我是我的头很难绕过在R中创建此列表结构所需的递归步骤。在JS我可以非常容易地在节点周围移动,并且在每个节点确定是添加新节点还是继续向下移动根据需要使用,例如:​​或new = {"name": node, "size": size};,如在此example中那样。我试图split的data.frame在本example

makeList<-function(x){ 
    if(ncol(x)>2){ 
     listSplit<-split(x,x[1],drop=T) 
     lapply(names(listSplit),function(y){list(name=y,children=makeList(listSplit[[y]]))}) 
    } else { 
     lapply(seq(nrow(x[1])),function(y){list(name=x[,1][y],size=x[,2][y])}) 
    } 
} 

jsonOut<-toJSON(list(name="root",children=makeList(path))) 

,但它给我一个错误

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

什么是您的数据帧是什么样子? – AmeliaBR

+0

@AmeliaBR我添加了数据框的输出。 –

+0

好的。是的,你有那里的信息,但我无法弄清楚它是如何表示树形结构的。现在我看到:每行代表从根到叶的路径。 [这是另一个类似数据结构的d3/javascript示例](http://stackoverflow.com/a/20964688/3128209),我将尝试在R中重新编写它。 – AmeliaBR

回答

1

linked Q&A中给出的函数基本上是您所需要的,但是由于后面的列中某些行的空值,所以它在数据集上失败。相反的,直到你用完列只是一味地重复递归,你需要检查你的“结束”值,并用它来切换到制作树叶:

makeList<-function(x){ 
    listSplit<-split(x[-1],x[1], drop=TRUE); 
    lapply(names(listSplit),function(y){ 
     if (y == "end") { 
      l <- list(); 
      rows = listSplit[[y]]; 
      for(i in 1:nrow(rows)) { 
       l <- c(l, list(name=y, size=rows[i,"size"])); 
      } 
      l; 

     } 
     else { 
      list(name=y,children=makeList(listSplit[[y]])) 
     } 
    }); 
} 
+0

非常感谢@AmeliaBR。这工作得很好。我正在用空单元格来解决问题,而不是按照你的解决方案做一些“最终”值。 –

+0

是的,空值看起来真的会抛出列表分割函数结果,所以最好在你到达之前进行干预,因为你的数据已经有了“叶子”位置的明确定义。 – AmeliaBR

0

我相信这是你想要的东西,虽然它有一定的局限性。特别是,假设你的网络中的每一个分支是唯一的(即不能有在您的数据帧两行相等比其他尺寸的每一列):

df.split <- function(p.df) { 
    p.lst.tmp <- unname(split(p.df, p.df[, 1])) 
    p.lst <- lapply(
    p.lst.tmp, 
    function(x) { 
     if(ncol(x) == 2L && nrow(x) == 1L) { 
     return(list(name=x[1, 1], size=unname(x[, 2]))) 
     } else if (isTRUE(is.na(unname(x[ ,2])))) { 
     return(list(name=x[1, 1], size=unname(x[, ncol(x)]))) 
     } 
     list(name=x[1, 1], children=df.split(x[, -1, drop=F])) 
    } 
) 
    p.lst 
} 
all.equal(rl, df.split(path)[[1]]) 
# [1] TRUE 

虽然注意到你有有机大小切换,所以我不得不修复你的rl得到这个结果(rl它有45,但你的path为23)。另外,我修改了path data.frame略:

path <- data.frame(
    root=rep("root", 4), 
    P1=c("direct","direct","organic","direct"), 
    P2=c("direct","direct","end","end"), 
    P3=c("direct","organic",NA,NA), 
    P4=c("end","end",NA,NA), 
    size=c(5,12,23,45), 
    stringsAsFactors=F 
) 

警告:我还没有和其他结构测试这一点,所以有可能会打,你需要调试角落的情况。

+0

谢谢@BrodieG - 这很好用。是的,每条路都是独一无二的。否则就已经在现有的路径中进行了总结。我也很感激你改变了输入数据帧格式以适合你的功能。 –