5
votes

Empilez une liste de dates nommée dans data.frame

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"
  • Remarque1: La longueur de chaque cellule est différente et les valeurs de la liste sont en fait une classe Date .
  • Remarque2: 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?


1 commentaires

Je modifie ma question. stack () ne fonctionne pas dans la liste de dates.


3 Réponses :


4
votes

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 

Update

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

Benchmarks

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


4 commentaires

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



3
votes

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


0 commentaires

3
votes

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


0 commentaires