Je fais un projet scolaire de nettoyage de données avec le package tidyverse
. Maintenant, j'obtiens une sortie de liste de purrr :: map ()
comme ceci:
df <- data.frame(Value = reduce(mylist, c)) df$Class <- rep(names(mylist), sapply(mylist, length)) df Value Class 1 1970-06-12 A 2 1984-05-28 A 3 1967-06-28 A 4 1982-12-14 A 5 1966-02-04 B 6 1967-02-21 B 7 1977-07-19 C 8 1968-03-11 C 9 1964-02-13 C
Je veux les empiler dans:
(mylist <- list(A = as.Date(sample(1e3:1e4, 4), origin = "1960-01-01"), B = as.Date(sample(1e3:1e4, 2), origin = "1960-01-01"), C = as.Date(sample(1e3:1e4, 3), origin = "1960-01-01"))) $A [1] "1970-06-12" "1984-05-28" "1967-06-28" "1982-12-14" $B [1] "1966-02-04" "1967-02-21" $C [1] "1977-07-19" "1968-03-11" "1964-02-13"
Date
. stack (myylist)
ne fonctionne pas dans la liste de dates. Existe-t-il des méthodes pour y parvenir efficacement avec des fonctions de tidyverse
ou d'autres packages?
3 Réponses :
Nous pouvons utiliser stack
system.time({rbindlist(lapply(mylist2, as.data.table), idcol = names(mylist2))}) # user system elapsed # 2.889 0.160 3.029 system.time({enframe(mylist2) %>% unnest}) # user system elapsed # 0.149 0.004 0.152 system.time({data.frame(value = reduce(mylist2, c), class = rep(names(mylist2), lengths(mylist2)))}) # user system elapsed # 14.714 8.890 23.550 library(microbenchmark) microbenchmark( ak1 = reshape2::melt(mylist2), ak2 = enframe(mylist2) %>% unnest, st1 = data.table::melt(mylist2), st2 = rbindlist(lapply(mylist2, as.data.table), idcol = names(mylist2)), unit = 'relative', times = 10L) #Unit: relative # expr min lq mean median uq max neval cld # ak1 26.51333 24.38488 21.52345 23.65577 19.36023 18.71291 10 c # ak2 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 10 a # st1 25.34465 24.56934 21.97353 26.27053 19.23078 17.32802 10 c # st2 16.19268 16.96023 14.28353 16.25288 12.69549 11.58340 10 b
Pour la question mise à jour, soit melt
de reshape2
ou data.table
peut être utilisé
mylist2 <- rep(mylist, 1e4) #slightly bigger list system.time({data.table::melt(mylist2)}) #Sotos solution #user system elapsed # 3.432 0.025 3.436 system.time({reshape2::melt(mylist2)}) #user system elapsed # 3.461 0.021 3.472
Ou en utilisant tidyverse
p>
library(tidyverse) enframe(mylist) %>% unnest # A tibble: 9 x 2 # name value # <chr> <date> #1 A 3658-09-23 #2 A 2390-06-01 #3 A 2744-01-09 #4 A 2432-02-21 #5 B 4077-11-13 #6 B 4022-11-13 #7 C 3923-11-19 #8 C 2836-08-20 #9 C 3411-01-23
Voici quelques benchmarks utilisant les quatre solutions postées
library(reshape2) melt(mylist) # value L1 #1 3658-09-23 A #2 2390-06-01 A #3 2744-01-09 A #4 2432-02-21 A #5 4077-11-13 B #6 4022-11-13 B #7 3923-11-19 C #8 2836-08-20 C #9 3411-01-23 C
Le melt Les fonctions
des deux packages n'ont qu'une légère différence de performances
stack(mylist) # values ind #1 1 A #2 2 A #3 3 A #4 4 B #5 5 B #6 6 B #7 7 B #8 8 C #9 9 C
Je modifie ma question. stack ()
ne fonctionne pas dans la liste de dates.
Désolé, au début, je pense que la solution d'une liste numérique équivaut à une liste de dates. Merci pour votre modification.
@DarrenTsai Je pense que les attributs de Date
ont créé un problème dans stack
. J'ai mis à jour avec une autre solution
ajouté cela dans la liste
Nous pouvons utiliser le package data.table
qui est très efficace,
data.table::melt(mylist)
De plus, data.table :: melt ()
fera également le travail (similaire à la solution reshape2
de @ akrun), c'est-à-dire
library(data.table) rbindlist(lapply(mylist, as.data.table), idcol = names(mylist)) # A V1 #1: A 4394-02-08 #2: A 4580-05-16 #3: A 2476-01-24 #4: A 2928-11-03 #5: B 4652-12-02 #6: B 3758-02-20 #7: C 2331-09-07 #8: C 3092-02-15 #9: C 3494-03-07
Nous avons déjà les solutions data.table
et tidyverse
(qui sont très efficaces) mais juste pour être complet, voici une approche de base R
data.frame(value = do.call(c, mylist), class = rep(names(mylist), lengths(mylist)))
Je modifie ma question.
stack ()
ne fonctionne pas dans la liste de dates.