R-liste à base de données

j'ai une liste imbriquée de données. Sa longueur est de 132 et chaque élément est une liste de longueur 20. Y a-t-il une façon rapide de convertir cette structure en une base de données qui a 132 lignes et 20 colonnes de données?

voici quelques exemples de données à utiliser:

l <- replicate(
  132,
  list(sample(letters, 20)),
  simplify = FALSE
)
396
demandé sur Philipp HB 2010-11-19 19:40:52

17 réponses

si votre liste de listes est appelée l :

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

ce qui précède convertira toutes les colonnes de caractères en facteurs, pour éviter cela, vous pouvez ajouter un paramètre aux données.image() appel:

df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
277
répondu nico 2015-03-17 08:36:28

avec rbind

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

Edit: version précédente retour data.frame de list 's au lieu de vecteurs (comme @IanSudbery l'a souligné dans les commentaires).

373
répondu Marek 2013-03-29 16:13:28

vous pouvez utiliser le paquet plyr . Par exemple, une liste imbriquée du formulaire

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

a maintenant une longueur de 4 et chaque liste dans l contient une autre liste de la longueur 3. Maintenant vous pouvez lancer

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

et devrait obtenir le même résultat que dans la réponse @Marek et @nico.

113
répondu mropa 2010-11-19 17:07:46

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

sapply le convertit en matrice. data.frame convertit la matrice en base de données.

77
répondu Alex Brown 2010-11-19 17:19:33

supposons que votre liste s'appelle L ,

data.frame(Reduce(rbind, L))
54
répondu jdeng 2014-03-24 14:49:15

le paquet data.table a la fonction rbindlist qui est une implémentation très rapide de do.call(rbind, list(...)) .

Il peut prendre une liste de lists , data.frames ou data.tables comme entrée.

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)

retourne un data.table hérite de data.frame .

Si vous vraiment voulez-vous convertir le retour à un ensemble de données.cadre d'utilisation as.data.frame(DT)

44
répondu mnel 2013-03-25 21:59:44

le paquet tibble a une fonction enframe() qui résout ce problème en forçant des objets imbriqués list à des objets imbriqués tibble (cadre de données "ordonné"). Voici un bref exemple de R pour la science des données :

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

puisque vous avez plusieurs nids dans votre liste, l , vous pouvez utiliser le unlist(recursive = FALSE) pour enlever les nids inutiles pour obtenir juste une liste hiérarchique simple et passer ensuite à enframe() . J'utilise tidyr::unnest() pour dénouer la sortie dans une base de données de niveau" ordonné", qui a vos deux colonnes (une pour le groupe name et une pour les observations avec les groupes value ). Si vous voulez des colonnes qui font large, vous pouvez ajouter une colonne en utilisant add_column() qui ne répète que l'ordre des valeurs 132 fois. Puis juste spread() les valeurs.



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>
17
répondu Matt Dancho 2017-04-10 20:15:21

Reshape2 fournit la même production que l'exemple de plyr ci-dessus:

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)

donne:

  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 vous étiez presque à court de pixels, vous pourriez faire tout cela en 1 ligne w/ recast().

15
répondu Jack Ryan 2013-05-16 19:26:14

plus de réponses, ainsi que des horaires dans la réponse à cette question: Quelle est la manière la plus efficace de lancer une liste comme base de données?

le moyen le plus rapide, qui ne produit pas de datagramme avec des listes plutôt que des vecteurs pour les colonnes semble être (de la réponse 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]])))
8
répondu Ian Sudbery 2017-05-23 12:26:33

pour le cas général des listes profondément imbriquées à 3 niveaux ou plus comme celles obtenues d'un JSON imbriqué:

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

tenir compte de l'approche de melt() pour convertir la liste imbriquée à un grand format de la première:

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

suivi de dcast() puis à nouveau à large dans un ensemble de données ordonné où chaque variable forme une colonne et chaque observation forme une rangée:

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
8
répondu ecerulm 2016-11-06 12:37:07

prolongeant la réponse de @Marek: si vous voulez éviter que les chaînes se transforment en facteurs et que l'efficacité ne soit pas une préoccupation, essayez

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
7
répondu laubbas 2015-04-28 10:31:40

Parfois, vos données peuvent être une liste de listes de vecteurs de même longueur.

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

(les vecteurs internes pourraient aussi être des listes, mais je simplifie pour faciliter la lecture).

, Alors vous pouvez faire la modification suivante. Rappelez-vous que vous pouvez désinscrire un niveau à la fois:

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

utilisez maintenant votre méthode préférée mentionnée dans les autres réponses:

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
6
répondu user36302 2016-10-27 18:34:41

C'est ce qui a finalement fonctionné pour moi:

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

4
répondu Amit Kohli 2015-12-11 11:15:24

selon la structure de vos listes il y a quelques options tidyverse qui fonctionnent bien avec des listes de longueur inégale:

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

vous pouvez également mélanger vecteurs et cadres de données:

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
3
répondu sbha 2018-07-11 02:07:45
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
2
répondu zhan2383 2016-04-20 17:48:48

cette méthode utilise un emballage tidyverse ( purrr ).

La liste:

x <- as.list(mtcars)

conversion en base de données (plus précisément un tibble ):

library(purrr)
map_df(x, ~.x)
2
répondu SavedByJESUS 2018-05-30 02:00:12

test1 < - list(c (A='A', b='b', c='c'), c(a='d', b='e', C= 'f')) comme.données.cadre(test1) a b c 1 a B c 2 d e f

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

as.données.cadre(test2) a b c 1 a B c 2 d e f

test3 < - list ('Row1'=c (A = 'A', b='b', c=' c'),'Row2'=c(A='d', var2='e', var3=' f'))

comme.données.cadre(essai3)) a b c var2 var3 Ligne 1 A B c

Row2 d e f

-3
répondu dileep balineni 2017-09-29 18:43:40