我正在使用tidyverse
软件包进行学校数据清理项目。现在,我从purrr::map()
中获得了列表输出,如下所示:
(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"
我想将它们堆叠到:
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
Date
类。stack(mylist)
在“日期”列表中不起作用。是否有任何方法可以使用tidyverse
或其他软件包中的函数来有效地实现它?
答案 0 :(得分:4)
我们可以使用stack
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
对于更新后的问题,可以使用melt
或reshape2
中的data.table
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
或使用tidyverse
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
以下是使用发布的四个解决方案的一些基准
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
两个软件包中的melt
函数在性能上只有细微的差别
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
答案 1 :(得分:3)
我们可以使用非常高效的data.table
软件包,
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
另外,data.table::melt()
也可以完成这项工作(类似于@akrun的reshape2
解决方案),即
data.table::melt(mylist)
答案 2 :(得分:3)
我们已经有了data.table
和tidyverse
解决方案(效率很高),但出于完整性考虑,这里是基本的R方法
data.frame(value = Reduce(c, mylist), class = rep(names(mylist), lengths(mylist)))
# value class
#1 1983-04-14 A
#2 1979-01-15 A
#3 1977-08-22 A
#4 1974-06-12 A
#5 1975-07-10 B
#6 1980-02-08 B
#7 1986-11-29 C
#8 1984-03-31 C
#9 1985-03-24 C
Reduce
也可以替换为do.call
data.frame(value = do.call(c, mylist), class = rep(names(mylist), lengths(mylist)))