2014-02-05 47 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 - 這很好用。是的,每條路都是獨一無二的。否則就已經在現有的路徑中進行了總結。我也很感激你改變了輸入數據幀格式以適合你的功能。 –