R-list to data frame
Tengo una lista anidada de datos. Su longitud es 132 y cada elemento es una lista de longitud 20. ¿Hay una forma rápida de convertir esta estructura en un marco de datos que tenga 132 filas y 20 columnas de datos?
Aquí hay algunos datos de muestra para trabajar con:
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
17 answers
Asumiendo que tu lista de listas se llama l
:
df <- data.frame(matrix(unlist(l), nrow=132, byrow=T))
Lo anterior convertirá todas las columnas de caracteres en factores, para evitar esto puede agregar un parámetro a los datos.llamada a frame ():
df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-17 08:36:28
Con rbind
do.call(rbind.data.frame, your_list)
Editar: La versión anterior devuelve data.frame
de list
's en lugar de vectores (como @IanSudbery señaló en los comentarios).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 16:13:28
Puede usar el paquete plyr
.
Por ejemplo, una lista anidada de la forma
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
Tiene ahora una longitud de 4 y cada lista en l
contiene otra lista de la longitud 3.
Ahora puedes ejecutar
library (plyr)
df <- ldply (l, data.frame)
Y debería obtener el mismo resultado que en la respuesta @Marek y @nico.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-19 17:07:46
data.frame(t(sapply(mylistlist,c)))
sapply
lo convierte en una matriz.
data.frame
convierte la matriz en un marco de datos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-19 17:19:33
Supongamos que su lista se llama L
,
data.frame(Reduce(rbind, L))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-24 14:49:15
El paquete data.table
tiene la función rbindlist
que es una implementación superrápida de do.call(rbind, list(...))
.
Puede tomar una lista de lists
, data.frames
o data.tables
como entrada.
library(data.table)
ll <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
DT <- rbindlist(ll)
Esto devuelve un data.table
heredado de data.frame
.
Si realmente desea convertir de nuevo a un dato.uso del marco as.data.frame(DT)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-25 21:59:44
El paquete tibble
tiene una función enframe()
que resuelve este problema coaccionando objetos anidados list
a objetos anidados tibble
("tidy" data frame). Aquí hay un breve ejemplo de R para la Ciencia de datos :
x <- list(
a = 1:5,
b = 3:4,
c = 5:6
)
df <- enframe(x)
df
#> # A tibble: 3 × 2
#> name value
#> <chr> <list>
#> 1 a <int [5]>
#> 2 b <int [2]>
#> 3 c <int [2]>
Dado que tiene varios nidos en su lista, l
, puede usar unlist(recursive = FALSE)
para eliminar el anidamiento innecesario para obtener una sola lista jerárquica y luego pasar a enframe()
. Utilizo tidyr::unnest()
para desmontar la salida en un marco de datos "ordenado" de un solo nivel, que tiene sus dos columnas (una para el grupo name
y uno para las observaciones con los grupos value
). Si desea columnas que sean amplias, puede agregar una columna usando add_column()
que simplemente repita el orden de los valores 132 veces. Entonces solo spread()
los valores.
library(tidyverse)
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
l_tib <- l %>%
unlist(recursive = FALSE) %>%
enframe() %>%
unnest()
l_tib
#> # A tibble: 2,640 x 2
#> name value
#> <int> <chr>
#> 1 1 d
#> 2 1 z
#> 3 1 l
#> 4 1 b
#> 5 1 i
#> 6 1 j
#> 7 1 g
#> 8 1 w
#> 9 1 r
#> 10 1 p
#> # ... with 2,630 more rows
l_tib_spread <- l_tib %>%
add_column(index = rep(1:20, 132)) %>%
spread(key = index, value = value)
l_tib_spread
#> # A tibble: 132 x 21
#> name `1` `2` `3` `4` `5` `6` `7` `8` `9` `10` `11`
#> * <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1 d z l b i j g w r p y
#> 2 2 w s h r i k d u a f j
#> 3 3 r v q s m u j p f a i
#> 4 4 o y x n p i f m h l t
#> 5 5 p w v d k a l r j q n
#> 6 6 i k w o c n m b v e q
#> 7 7 c d m i u o e z v g p
#> 8 8 f s e o p n k x c z h
#> 9 9 d g o h x i c y t f j
#> 10 10 y r f k d o b u i x s
#> # ... with 122 more rows, and 9 more variables: `12` <chr>, `13` <chr>,
#> # `14` <chr>, `15` <chr>, `16` <chr>, `17` <chr>, `18` <chr>,
#> # `19` <chr>, `20` <chr>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-10 20:15:21
Reshape2 produce la misma salida que el ejemplo plyr anterior:
library(reshape2)
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
l <- melt(l)
dcast(l, L1 ~ L2)
Rinde:
L1 var.1 var.2 var.3
1 a 1 2 3
2 b 4 5 6
3 c 7 8 9
4 d 10 11 12
Si estuviera casi sin píxeles, podría hacer todo esto en 1 línea con recast().
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 19:26:14
Más respuestas, junto con los tiempos en la respuesta a esta pregunta: ¿Cuál es la forma más eficiente de convertir una lista como un marco de datos?
La forma más rápida, que no produce un dataframe con listas en lugar de vectores para columnas parece ser (de la respuesta de Martin Morgan):
l <- list(list(col1="a",col2=1),list(col1="b",col2=2))
f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE)
as.data.frame(Map(f(l), names(l[[1]])))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:33
Para el caso general de listas profundamente anidadas con 3 o más niveles como las que se obtienen de un JSON anidado:
{
"2015": {
"spain": {"population": 43, "GNP": 9},
"sweden": {"population": 7, "GNP": 6}},
"2016": {
"spain": {"population": 45, "GNP": 10},
"sweden": {"population": 9, "GNP": 8}}
}
Considere el enfoque de melt()
para convertir la lista anidada a un formato alto primero:
myjson <- jsonlite:fromJSON(file("test.json"))
tall <- reshape2::melt(myjson)[, c("L1", "L2", "L3", "value")]
L1 L2 L3 value
1 2015 spain population 43
2 2015 spain GNP 9
3 2015 sweden population 7
4 2015 sweden GNP 6
5 2016 spain population 45
6 2016 spain GNP 10
7 2016 sweden population 9
8 2016 sweden GNP 8
Seguido de dcast()
luego de nuevo a ancho en un conjunto de datos ordenado donde cada variable forma una columna y cada observación forma una fila:
wide <- reshape2::dcast(tall, L1+L2~L3)
# left side of the formula defines the rows/observations and the
# right side defines the variables/measurements
L1 L2 GNP population
1 2015 spain 9 43
2 2015 sweden 6 7
3 2016 spain 10 45
4 2016 sweden 8 9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-06 12:37:07
Extendiendo la respuesta de @ Marek: si quieres evitar que las cadenas se conviertan en factores y la eficiencia no es una preocupación, intenta
do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 10:31:40
A veces sus datos pueden ser una lista de listas de vectores de la misma longitud.
lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )
(Los vectores internos también podrían ser listas, pero estoy simplificando para hacer esto más fácil de leer).
Entonces puede hacer la siguiente modificación. Recuerda que puedes dejar de listar un nivel a la vez:
lov = unlist(lolov, recursive = FALSE )
> lov
[[1]]
[1] 1 2 3
[[2]]
[1] 4 5 6
[[3]]
[1] 7 8 9
[[4]]
[1] 10 11 12
[[5]]
[1] 13 14 15
Ahora usa tu método favorito mencionado en las otras respuestas:
library(plyr)
>ldply(lov)
V1 V2 V3
1 1 2 3
2 4 5 6
3 7 8 9
4 10 11 12
5 13 14 15
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-27 18:34:41
Esto es lo que finalmente funcionó para mí:
do.call("rbind", lapply(S1, as.data.frame))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 11:15:24
Dependiendo de la estructura de sus listas, hay algunas opciones tidyverse
que funcionan bien con listas de longitud desigual:
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5)
, c = list(var.1 = 7, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = NA))
df <- dplyr::bind_rows(l)
df <- purrr::map_df(l, dplyr::bind_rows)
df <- purrr::map_df(l, ~.x)
# all create the same data frame:
# A tibble: 4 x 3
var.1 var.2 var.3
<dbl> <dbl> <dbl>
1 1 2 3
2 4 5 NA
3 7 NA 9
4 10 11 NA
También puede mezclar vectores y marcos de datos:
library(dplyr)
bind_rows(
list(a = 1, b = 2),
data_frame(a = 3:4, b = 5:6),
c(a = 7)
)
# A tibble: 4 x 2
a b
<dbl> <dbl>
1 1 2
2 3 5
3 4 6
4 7 NA
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-11 02:07:45
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-20 17:48:48
Este método utiliza un paquete tidyverse
( purrr).
La lista:
x <- as.list(mtcars)
Convertirlo en un marco de datos (a tibble
más específicamente):
library(purrr)
map_df(x, ~.x)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-30 02:00:12
Test1
Test2
As.datos.marco(test2) a b c 1 a b c 2 d e f
Test3
As.datos.marco(test3) a b c var2 var3 Fila 1 a b c
Fila 2 d e f
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-29 18:43:40