说我有
library(dplyr)
a <- list(a=tbl_df(cars), b=tbl_df(iris))
如何向列表的每个元素添加一列name
,其值是列表中指定元素的名称?
例如,这对于第一个元素
Source: local data frame [50 x 3]
speed dist name
(dbl) (dbl) (chr)
1 4 2 a
2 4 10 a
3 7 4 a
4 7 22 a
5 8 16 a
6 9 10 a
7 10 18 a
8 10 26 a
9 10 34 a
10 11 17 a
答案 0 :(得分:2)
在所有这些评论之后,我猜我会写一个答案。
您应该使用for
循环:它可以快速编写代码,快速执行,可读且直接:
for (i in seq_along(a)) a[[i]]$name = names(a)[i]
您可以使用map
或mapply
或lapply
代替for循环。在这种情况下,我认为它的可读性会降低。
您还可以使用mutate
代替[
来添加列。这会慢一点:
library(microbenchmark)
library(dplyr)
cars_tbl = tbl_df(cars)
mbm = microbenchmark
mbm(
mutate = {cars_tbl = mutate(cars_tbl, name = 'a')},
base = {cars_tbl['name'] = 'a'}
)
# Unit: microseconds
# expr min lq mean median uq max neval cld
# mutate 240.617 262.4730 293.29001 276.158 299.7255 813.078 100 b
# base 34.971 42.1935 55.46356 53.407 57.3980 226.932 100 a
对于这样一个简单的操作,[<-
将很难被击败。 data.table
可能会更快,但前提是该对象已经是data.table
。如果对象是data.frame
而不是tbl_df
,那么mutate
的速度大约是dplyr
的两倍。 但这些差异只有几微秒。除非您反复对至少数十万个数据框的列表执行此操作,否则无关紧要。
这并不是说dplyr
性能不佳 - 当您使用分组操作时,依赖于内置于df = tbl_df(data.frame(x = rep(1, 1e7)))
mbm(
mutate = {df = mutate(df, name = 'a')},
base = {df['name'] = 'a'}
)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# mutate 58.08095 59.87531 132.3180 105.22507 207.6439 261.8121 100 a
# base 52.09899 53.96386 129.9304 99.96153 203.8581 237.0084 100 a
的NSE,它非常出色。这只是一个简单的基本解决方案最简单,也是最快的简单案例。
如果我们增加足够的数据大小以便花费相当多的时间来执行这些操作(此处为1000万行),差异基本上消失了:
for
使用map
循环和[<-
进行实施,比较mutate
和# base for loop
for (i in seq_along(a)) {
a[[i]]$name = names(a)[i]
}
# dplyr in for loop
for (i in seq_along(a)) {
a[[i]] = mutate(a[[i]], name = names(a)[i])
}
# dplyr hiding the loop in Map()
a = Map(function(x, y) mutate(x, name = y), x = a, y = names(a))
name
我们可以对这些进行基准测试(我做了 - 如果你想要结果,请查看编辑历史记录),但差异小于1毫秒因此它不重要。选择最简单的东西来阅读,书写和理解。
所有这些都伴随着警告,如果您的最终目标是将这些数据框绑定在一起,并且您希望dplyr::bind_rows
列查看数据来自哪个列表元素,那么直接在{{1 }}。