2010-02-14 7 views
6

Tengo datos experimentales expresados ​​como dicts de pares clave-valor para cada experimento. Un conjunto de experimentos relacionados se serializa como una lista de estos dicts en JSON. Esto es analizable en en R a través del paquete rjson, pero los datos se cargan en una forma que es un reto para analizarTransposición de la lista de diccionarios JSON para el análisis en R

data <- fromJSON('[{"k1":"v1","k2":"v2"}, {"k1":"v3","k2":"v4"}]') 

rendimientos

[[1]] 
[[1]]$k1 
[1] "v1" 

[[1]]$k2 
[1] "v2" 


[[2]] 
[[2]]$k1 
[1] "v3" 

[[2]]$k2 
[1] "v4" 

El intento de convertir esto en un data.frame directamente con as.data.frame(data) rendimientos :

k1 k2 k1.1 k2.1 
1 v1 v2 v3 v4 

claramente viendo la secuencia de pares clave/valor en todos los experimentos como una lista plana de 1 dimensión.

Lo que quiero es una tabla más convencional con una fila para cada experimento, y una columna para cada clave única:

k1 k2 
1 v1 v2 
2 v3 v4 

¿Cómo puedo expresar limpiamente esta transformada en R?

Respuesta

11

Las funciones l*ply pueden ser su mejor amigo al hacer con el procesamiento de listas. Prueba esto:

> library(plyr) 
> ldply(data, data.frame) 
    k1 k2 
1 v1 v2 
2 v3 v4 

plyr hace algún procesamiento muy agradable detrás de las escenas que lidiar con cosas como listas irregulares (por ejemplo, cuando cada lista no contiene el mismo número de elementos). Esto es muy común con JSON y XML, y es difícil de manejar con las funciones básicas.

O, alternativamente, utilizando funciones de base:

> do.call("rbind", lapply(data, data.frame)) 

Le ofrecemos rbind.fill (de plyr) en lugar de rbind si tiene listas irregulares, pero te aconsejo usar sólo plyr desde el principio para hacer su vida más fácil .

Editar:

En cuanto a su ejemplo más complicado, con ofertas de sugerencia de Hadley con esta facilidad:

> x<-list(list(k1=2,k2=3),list(k2=100,k1=200),list(k1=5, k3=9)) 
> ldply(x, data.frame) 
    k1 k2 k3 
1 2 3 NA 
2 200 100 NA 
3 5 NA 9 
+0

Al igual que la solución plyr, ya que puede tratar las variables que aparecen en un orden diferente para cada observación. Llámame paranoico, pero me preocuparon algunas observaciones que no tienen algunas variables. Aquí hay una variación que no funciona ni siquiera para casos muy malos: x <-list (lista (k1 = 2, k2 = 3), lista (k2 = 100, k1 = 200), lista (k1 = 5)) ; ldply (x, function (z) as.data.frame (t (unlist (z))) –

+2

Creo que una mejor solución es 'ldply (x, data.frame)' – hadley

+0

Siempre elegiría la solución plyr:) –

4

Esto es interesante. La manera más fácil sería arreglar el código de Python para que el dict se pueda transformar más fácilmente.

Pero, ¿qué tal esto?

k1 <- unlist(lapply(data,FUN=function(x){return(x[[1]])})) 
k2 <- unlist(lapply(data,FUN=function(x){return(x[[2]])})) 
data.frame(k1,k2) 

Tendrá que echar k1 y k2 en el tipo de datos correcto todavía, pero esto debe lograr lo que busca.

+2

Una generalización más limpia si tiene una gran cantidad de columnas serían: NewData <- lapply (1: length (data [[1]]), function (x) unlist (lapply (data, "[[", x))); newdata <- as.data.frame (newdata); names (newdata) <- names (data [[1]]) – brentonk

+0

Claramente puedo preprocesar el JSON para transponerlo antes de cargarlo, pero el problema es que no lo veo como "arreglo": una lista de dicts _es_ la forma más natural de pensar en estos datos.Un dict de listas es la forma más conveniente para que el software orientado a filas lo cargue densamente, no es la mejor manera de pensarlo. Y desempaquetar manualmente cada entrada es insostenible. El método de Bretonk, sin embargo, funciona. (Claramente necesito entender mejor el significado de '[['en comparación con el subconjunto normal (' ['), entre otras cosas.] – jrk

+0

Mi solución funciona para dos columnas, que es claramente lo que su pregunta implicaba. Si tiene varias columnas, entonces por supuesto necesita usar una generalización, como el método de brentonk. –