2011-12-12 18 views
13

Tengo que hacer frente a una lista fea llamada ul que tiene este aspecto:Lista de listas de trama de datos en I

[[1]] 
[[1]]$param 
    name  value 
"Section"  "1" 

[[1]]$param 
    name value 
"field"  "1" 

[[1]]$param 
      name   value 
"final answer"   "1" 

[[1]]$param 
    name value 
"points" "-0.0" 


[[2]] 
[[2]]$param 
    name  value 
"Section"  "1" 

[[2]]$param 
    name value 
"field"  "2" 

[[2]]$param 
      name   value 
"final answer"   "1" 

[[2]]$param 
    name value 
"points" "1.0" 


[[3]] 
[[3]]$param 
    name  value 
"Section"  "1" 

[[3]]$param 
    name value 
"field"  "3" 

[[3]]$param 
      name   value 
"final answer"  "0.611" 

[[3]]$param 
    name value 
"points" "1.0" 

me gustaría convertir la lista a una trama de datos simple, es decir

Section field final answer points 
     1  1    1  -0.0 
     1  2    1  1.0 
     1  3   0.611  1.0 

¿Hay alguna manera directa de lograr eso? ¿o tengo que hacer una función que acceda individualmente a cada lista y vincularla a un marco de datos?

Los datos se importan de un archivo xml más feo, por lo que si alguien quiere jugar con él hay un enlace al RData file. Perdón por no tener código reproducible. Muchas gracias.

Respuesta

12

Probablemente haya una solución mejor, pero esto debería comenzar. Primero, cargamos algunas bibliotecas

R> library(plyr) 
R> library(reshape2) 

Luego maneje sus listas en dos partes.

##lapply applies ldply to each list element in turn 
ul1 = lapply(ul, ldply) 

##We then do the same again 
dd = ldply(ul1)[,2:3] 

continuación etiquetar los resultados de acuerdo a su orden de la lista

R> dd$num = rep(1:3, each=4) 

Luego convertimos de largo a gran formato

R> dcast(dd, num ~ name) 

    num field final answer points Section 
1 1  1   1 -0.0  1 
2 2  2   1 1.0  1 
3 3  3  0.611 1.0  1 
9

A medida que la estructura de la ul es consistente, puede simplemente obtener cada columna individualmente (utilizando solo la base R):

section <- vapply(ul, function(x) as.numeric(x[[1]][2]), 0) 
field <- vapply(ul, function(x) as.numeric(x[[2]][2]), 0) 
final_answer <- vapply(ul, function(x) as.numeric(x[[3]][2]), 0) 
points <- vapply(ul, function(x) as.numeric(x[[4]][2]), 0) 

(Tenga en cuenta que utilizo vapply en lugar de ya que es más rápido y devuelve de manera confiable un vector, que es necesario aquí).
A continuación, puede poner todo junto:

> data.frame(section, field, final_answer, points) 
    section field final_answer points 
1  1  1  1.000  0 
2  1  2  1.000  1 
3  1  3  0.611  1 

Tenga en cuenta que he transformado todo en numeric. Si desea conservar todo como caracteres, elimine as.numeric e intercambie 0 con "" en cada llamada al vapply.


tardía actualización:

En realidad, hay un buen oneliner que extrae los datos completos:

do.call("rbind", lapply(ul, function(x) as.numeric(vapply(x, "[", i = 2, "")))) 

lo que da:

 [,1] [,2] [,3] [,4] 
[1,] 1 1 1.000 0 
[2,] 1 2 1.000 1 
[3,] 1 3 0.611 1 

Para obtener el uso colnames :

> vapply(ul[[1]], "[", i = 1, "") 
     param   param   param   param 
    "Section"  "field" "final answer"  "points" 
1

no estoy seguro de lo que quiere decir con "una función de acceso a cada lista individual", pero esto es bastante sencillo utilizando "lapply" y "do.call ('rbind', ...)":

No pude cargar su.rdata archivo, por lo que este código funciona para la lista:

ul <- list(param = list(
      c(name = "Section", value = "1"), 
      c(name = "field", value = "1"), 
      c(name = "final answer", value = "1"), 
      c(name = "points", value = "-0.0")), 
      param = list(
      c(name = "Section", value = "1"), 
      c(name = "field", value = "2"), 
      c(name = "final answer", value = "1"), 
      c(name = "points", value = "1.0"))) 

Es posible que tenga que ajustar los detalles si su lista es diferente; el director general seguirá siendo el mismo. Para mantener el código limpio, definamos la función 'extractitem' que va a extraer todos los nombres o valores para ul [[1]], ul [[2]], etc. Esta función es un poco más general que necesitas.

extractitem <- function(listelement, item) 
    unname(lapply(listelement, function(itemblock) itemblock[item])) 

Ahora vamos a utilizar simplemente aplicar para caminar a través de elemento ul por elemento; para cada elemento, extraemos los valores en un marco de datos, luego nombramos las columnas de acuerdo con los 'nombres'.

rowlist <- lapply(ul, function(listelement) { 
    d <- data.frame(extractitem(listelement, "value"), stringsAsFactors = FALSE) 
    names(d) <- unlist(extractitem(listelement, "name")) 
    d 
}) 

lista de filas ahora es una lista de marcos de datos; podemos consolidarlos en un único marco de datos con 'rbind'. Lo bueno de utilizar marcos de datos en el paso anterior (a diferencia de vectores o algo con sobrecarga) es que rbind reordenará las columnas si es necesario, por lo que si el orden de los campos cambia de elemento a elemento, todavía somos todos derecho.

finaldf <- do.call("rbind", rowlist) 

Todavía tenemos que cambiar los elementos fo finaldf de "carácter" a lo que es apropiado para su aplicación a través de, por ejemplo,

finaldf$points <- as.numeric(finaldf$points) 

y así sucesivamente. El último paso se limpia la trama de datos por extracción de los nombres de las filas generadas automáticamente:

rownames(finaldf) <- NULL 

En caso de tener que modificar las cosas, la idea general es escribir una función que va a dar formato a cada ul [[i]] como un marco de datos con los nombres de columna correctos; luego invoque esa función en cada elemento de ul con lapply; y finalmente colapsar la lista resultante con do.call ("rbind", ...).

10

Una respuesta a un problema similar fue dada por Marc Schwartz en este enlace: https://stat.ethz.ch/pipermail/r-help/2006-August/111368.html

estoy copiando en caso se elimina el enlace.

as.data.frame(sapply(a, rbind)) 

    V1 V2 V3 
1 a b c 
2 1 3 5 
3 2 4 6 

o:

as.data.frame(t(sapply(a, rbind))) 
    V1 V2 V3 
1 a 1 2 
2 b 3 4 
3 c 5 6 
+0

Gracias por el enlace, yo no era consciente de ello cuando hice la pregunta. – Emer

+0

¡De nada! – rafaelvalle