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
)
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)
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).
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.
data.frame(t(sapply(mylistlist,c)))
sapply
le convertit en matrice.
data.frame
convertit la matrice en base de données.
supposons que votre liste s'appelle L
,
data.frame(Reduce(rbind, L))
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)
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>
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().
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]])))
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
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))
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
C'est ce qui a finalement fonctionné pour moi:
do.call("rbind", lapply(S1, as.data.frame))
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
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
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)
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