R – lista para o frame de dados

Eu tenho uma lista aninhada de dados. Seu comprimento é 132 e cada item é uma lista de comprimento 20. Existe uma maneira rápida de converter essa estrutura em um quadro de dados que tenha 132 linhas e 20 colunas de dados?

Aqui estão alguns dados de amostra para trabalhar com:

l <- replicate( 132, list(sample(letters, 20)), simplify = FALSE ) 

Supondo que sua lista de listas é chamada l :

 df < - data.frame(matrix(unlist(l), nrow=132, byrow=T)) 

O acima irá converter todas as colunas de caracteres para fatores, para evitar isso você pode adicionar um parâmetro para a chamada data.frame ():

 df < - data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE) 

Com rbind

 do.call(rbind.data.frame, your_list) 

Edit: Versão anterior retorna data.frame da list em vez de vetores (como @IanSudbery apontou nos comentários).

Você pode usar o pacote plyr . Por exemplo, uma lista aninhada do formulário

 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) ) 

tem agora um comprimento de 4 e cada lista em l contém outra lista do comprimento 3. Agora você pode executar

  library (plyr) df < - ldply (l, data.frame) 

e deve obter o mesmo resultado que na resposta @Marek e @nico.

data.frame(t(sapply(mylistlist,c)))

sapply converte para uma matriz. data.frame converte a matriz em um quadro de dados.

suponha que sua lista é chamada L ,

 data.frame(Reduce(rbind, L)) 

O pacote data.table tem a function rbindlist que é uma implementação super rápida do do.call(rbind, list(...)) .

Pode levar uma lista de lists , data.frames ou data.tables como input.

 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) 

Isso retorna um data.table herda de data.frame .

Se você realmente deseja converter de volta para um uso as.data.frame(DT)

O pacote tibble possui uma function enframe() que resolve esse problema ao coagir objects de list aninhada para objects de frameworks de dados tibble (“tidy”) nesteds. Aqui está um breve exemplo de R para Data Science :

 x < - list( a = 1:5, b = 3:4, c = 5:6 ) df <- enframe(x) df #> # A tibble: 3 × 2 #> name value #>   #> 1 a  #> 2 b  #> 3 c  

Como você tem vários ninhos na sua lista, l , você pode usar o unlist(recursive = FALSE) para remover o aninhamento desnecessário para obter apenas uma lista hierárquica e, em seguida, passar para o enframe() . Eu uso tidyr::unnest() para unnest a saída em um quadro de dados de nível único “tidy”, que tem suas duas colunas (uma para o name do grupo e uma para as observações com o value grupos). Se você quiser colunas que tornem largas, você pode adicionar uma coluna usando add_column() que apenas repete a ordem dos valores 132 vezes. Então apenas spread() os 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 #>   #> 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` #> *             #> 1 1 dzlbijgwrpy #> 2 2 wshrikduafj #> 3 3 rvqsmujpfai #> 4 4 oyxnpifmhlt #> 5 5 pwvdkalrjqn #> 6 6 ikwocnmbveq #> 7 7 cdmiuoezvgp #> 8 8 fseopnkxczh #> 9 9 dgohxicytfj #> 10 10 yrfkdobuixs #> # ... with 122 more rows, and 9 more variables: `12` , `13` , #> # `14` , `15` , `16` , `17` , `18` , #> # `19` , `20`  

Reshape2 produz a mesma saída que o exemplo plyr acima:

 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) 

rendimentos:

  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 

Se você estivesse quase sem pixels, poderia fazer isso tudo em uma linha com reformulação ().

Mais respostas, juntamente com intervalos na resposta a esta pergunta: Qual é a maneira mais eficiente de lançar uma lista como um quadro de dados?

A maneira mais rápida, que não produz um dataframe com listas em vez de vetores para colunas, parece ser (da resposta 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]]))) 

Para o caso geral de listas profundamente aninhadas com três ou mais níveis, como os obtidos de um JSON nested:

 { "2015": { "spain": {"population": 43, "GNP": 9}, "sweden": {"population": 7, "GNP": 6}}, "2016": { "spain": {"population": 45, "GNP": 10}, "sweden": {"population": 9, "GNP": 8}} } 

considere a abordagem de melt() para converter a lista aninhada para um formato alto primeiro:

 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 por dcast() depois novamente para um dataset arrumado onde cada variável forma uma coluna e cada observação forma uma linha:

 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 

Estendendo a resposta de @ Marek: se você quer evitar que as strings sejam transformadas em fatores, a eficiência não é uma preocupação.

 do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE)) 

Às vezes, seus dados podem ser uma lista de listas de vetores do mesmo tamanho.

 lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) ) 

(Os vetores internos também podem ser listas, mas estou simplificando para facilitar a leitura).

Então você pode fazer a seguinte modificação. Lembre-se de que você pode anular um nível por 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 

Agora use o seu método favorito mencionado nas outras respostas:

 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 

Isso é o que finalmente funcionou para mim:

do.call("rbind", lapply(S1, as.data.frame))

 l < - replicate(10,list(sample(letters, 20))) a <-lapply(l[1:10],data.frame) do.call("cbind", a) 

Este método usa um pacote tidyverse ( purrr ).

A lista:

 x < - as.list(mtcars) 

Convertendo-o em um quadro de dados (um tibble mais especificamente):

 library(purrr) map_df(x, ~.x) 

Dependendo da estrutura de suas listas, existem algumas opções que funcionam bem com listas de comprimentos desiguais:

 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    1 1 2 3 2 4 5 NA 3 7 NA 9 4 10 11 NA 

Você também pode misturar vetores e frameworks de dados:

 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 ab   1 1 2 2 3 5 3 4 6 4 7 NA 

test1 < - list (c (a = 'a', b = 'b', c = 'c'), c (a = 'd', b = 'e', ​​c = 'f')) as.data .frame (test1) abc 1 abc 2 def

test2 < - list (c ('a', 'b', 'c'), c (a = 'd', b = 'e', ​​c = 'f'))

as.data.frame (test2) abc 1 abc 2 def

test3 < - list ('Linha1' = c (a = 'a', b = 'b', c = 'c'), 'Linha2' = c (a = 'd', var2 = 'e', ​​var3 = 'f'))

as.data.frame (test3) abc var2 var3 Row1 abc
Row2 def