2012-10-10 29 views
17

Quiero convertir un hoja.de.datos R en un objeto JSON con el fin de utilizarlo para la preparación de visualizaciones de datos con d3.js. Encontré muchas preguntas que preguntaban cómo hacer que JSON entrara en R, pero muy pocas sobre cómo escribir datos de R a JSON.cómo escribir en JSON con niños de R

Un problema particular es que el archivo JSON necesita ser anidado utilizando factores, es decir, columnas de la data.frame. Creo que la escritura de las listas anidadas podría ser una solución, pero ya no pudo crear una lista anidada de un hoja.de.datos :(

He preprared un ejemplo:

esto representa mi hoja.de.datos (llamado . "MyData")

ID Location Station Size Percentage 
1  Alpha Zeta Big  0.63 
2  Alpha Zeta Medium  0.43 
3  Alpha Zeta small  0.47 
4  Alpha Yota Big  0.85 
5  Alpha Yota Medium  0.19 
6  Alpha Yota small  0.89 
7  Beta Theta Big  0.09 
8  Beta Theta Medium  0.33 
9  Beta Theta small  0.79 
10  Beta Meta Big  0.89 
11  Beta Meta Medium  0.71 
12  Beta Meta small  0.59 

ahora, quiero convertirlo en algo parecido a este formato JSON válida, incluyendo los nodos hijos:

{ 
"name":"MyData", 
"children":[ 
    { 
    "name":"Alpha", 
    "children":[ 
     { 
      "name":"Zeta", 
      "children":[ 
       { 
       "name":"Big", 
       "Percentage":0.63 
       }, 
       { 
       "name":"Medium", 
       "Percentage":0.43 
       }, 
       { 
       "name":"Small", 
       "Percentage":0.47 
       } 
      ] 
     }, 
     { 
      "name":"Yota", 
      "children":[ 
       { 
       "name":"Big", 
       "Percentage":0.85 
       }, 
       { 
       "name":"Medium", 
       "Percentage":0.19 
       }, 
       { 
       "name":"Small", 
       "Percentage":0.89 
       } 
      ] 
     } 
    ] 
}, 
    { 
    "name":"Zeta", 
    "children":[ 
     { 
      "name":"Big", 
      "Percentage":0.63 
     }, 
     { 
      "name":"Medium", 
      "Percentage":0.43 
     }, 
     { 
      "name":"Small", 
      "Percentage":0.47 
     } 
    ] 
    }, 
    { 
    "name":"Yota", 
    "children":[ 
     { 
      "name":"Big", 
      "Percentage":0.85 
     }, 
     { 
      "name":"Medium", 
      "Percentage":0.19 
     }, 
     { 
      "name":"Small", 
      "Percentage":0.89 
     } 
    ] 
    } 
    ] 
} 

Si alguien puede ayudarme ¡Estaría muy agradecido! gracias

+1

OMI, esto no tiene nada que ver con JSON per se, simplemente se asemejan a esta estructura dentro de R, y ya está bueno para ir. – aL3xa

+0

tienes razón, esto no es nada específico de JSON. mi pregunta era principalmente sobre cómo obtener esta estructura específica. – Jens

Respuesta

23

Este es un enfoque recursivo que es más limpio:

require(RJSONIO) 

makeList<-function(x){ 
    if(ncol(x)>2){ 
    listSplit<-split(x[-1],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],Percentage=x[,2][y])}) 
    } 
} 


jsonOut<-toJSON(list(name="MyData",children=makeList(MyData[-1]))) 
cat(jsonOut) 
+0

¡increíble! Ahora se ve perfecto. 100% válido json. Para hacer que d3js funcione con la salida, tuve que cambiar el "Porcentaje" a "tamaño". ¡Pero tu enfoque es absolutamente brillante! Espero poder ajustarlo/ampliarlo. Billion gracias! – Jens

+1

Esto puede ser adaptado a las jerarquías archivos normales no (es decir, cuando el número de jerarquías no es constante) mediante la adición de un filtro sencillo:

x2 <- dplyr::filter(x, x[1] != "") ; listSplit <- split(x2[-1], x2[1], drop = TRUE)
PAC

+0

@PAC exactamente donde hace una gota en 'x2 <- filtro (x, x [1]! = ""); listSplit <- split (x2 [-1], x2 [1], la caída = VERDADERO) '' justo después si (ncol (x)> 2) { 'y dejar todo lo demás igual? –

2

Usando una combinación de split y subset puede obtener lo que desea. Por ejemplo

library(RJSONIO) 
list1<-split(subset(MyData,select=c(-Location)),Mydata$Location) 
list2<-lapply(list1,function(x){split(subset(x,select=c(-Station)),x$Station,drop=TRUE)}) 
list3<-lapply(list2,function(x){lapply(x,function(y){split(subset(y,select=c(-Size,-ID)),y$Size,drop=TRUE)})}) 
jsonOut<-toJSON(list(MyData=list3)) 
jsonOut1<-gsub('([^\n]*?): \\{\n "Percentage"','\\{"name":\\1,"Percentage"',jsonOut) 
jsonOut2<-gsub('"([^"]*?)": \\{','"name":"\\1","children":\\{',jsonOut1) 

cat(jsonOut2) 
{ 
"name":"MyData","children":{ 
"name":"Alpha","children":{ 
"name":"Yota","children":{ 
{"name": "Big","Percentage": 0.85 
}, 
{"name":"Medium","Percentage": 0.19 
}, 
{"name":"small","Percentage": 0.89 
} 
}, 
"name":"Zeta","children":{ 
{"name": "Big","Percentage": 0.63 
}, 
{"name":"Medium","Percentage": 0.43 
}, 
{"name":"small","Percentage": 0.47 
} 
} 
}, 
"name":"Beta","children":{ 
"name":"Meta","children":{ 
{"name": "Big","Percentage": 0.89 
}, 
{"name":"Medium","Percentage": 0.71 
}, 
{"name":"small","Percentage": 0.59 
} 
}, 
"name":"Theta","children":{ 
{"name": "Big","Percentage": 0.09 
}, 
{"name":"Medium","Percentage": 0.33 
}, 
{"name":"small","Percentage": 0.79 
} 
} 
} 
} 
} 
+0

sí ¡interesante! pero aquí las variables '" Tamaño "' y '" Porcentaje "' están separadas. Cada estado de la variable, es decir, Grande, debe estar vinculado a su valor de Porcentaje en una sola fila. También falta el agrupamiento '' niños ''. Trataré de jugar con tu idea de dividir listas. THX – Jens

+0

he añadido una división en 'size' y algunas expresiones regulares feo. No es exactamente lo que quieres, pero quizás esté cerca. – user1609452

+0

aaah ahora entiendo cómo funciona eso. Gracias. Aunque todavía no está funcionando del todo, te votaré :) El validador de json ahora se está quejando. Creo que faltan los corchetes []. Trataré de arreglar esto ajustando tus ejemplos de expresiones regulares. – Jens

0

estoy Pigging dar marcha atrás de la respuesta de user1609452 y responder a la pregunta acerca de las jerarquías de archivos que no regulares. Si usted tiene una columna en la que algunos datos tienen los niños y otros no, usa la siguiente:

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

Básicamente comprobar si la fila actual tiene más hijos o si simplemente necesita tener el tamaño anexa a la misma.

Cuestiones relacionadas