将dplyr与across一起使用,做这些操作更灵活
library(dplyr)
df %>%
group_by(date) %>%
summarise(user = n(), across(c(turnover, profit), sum))
-输出
# A tibble: 2 x 4
date user turnover profit
<dbl> <int> <int> <int>
1 1 2 5 3
2 2 2 9 7
或者collapse 中的另一个选项来自构建data.table 的同一团队,其唯一目的是提高效率。
library(collapse)
collap(df, ~ date, custom = list(fsum = c("turnover", "profit"),
fNobs = "turnover"))
date fsum.turnover fNobs.turnover fsum.profit
1: 1 5 2 3
2: 2 9 2 7
基准测试
在更大的数据集上测试
library(data.table)
library(dplyr)
library(collapse)
library(purrr)
# input data
set.seed(24)
df1 <- data.table(date = rep(1:1e6, each = 20),
user = rep(1:1e6, 20),
turnover = rnorm(1e6 * 20),
profit = rnorm(1e6 * 20))
# benchmarks
# - B. Christian Kamgang
system.time({
df1[, c(.(user=.N), lapply(.SD, sum)), by=date, .SDcols=c("turnover", "profit")]
})
#user system elapsed
#0.558 0.110 0.670
# - Uwe
# - first
system.time({
df1[, c(.SD[, lapply(.SD, length), .SDcols = c("user")],
.SD[, lapply(.SD, sum), .SDcols = c("turnover", "profit")]), by = date]
})
#Timing stopped at: 245.9 3.336 249.4 0 stopped as it was taking time
# - second
system.time({
df1[, purrr::map2(list(length, sum, sum), .SD, \(fn, args) purrr::exec(fn, args)), by = date]
})
#user system elapsed
#37.816 0.138 38.016
# - third
system.time({
df1[, {
fct <- c("length", "sum", "sum")
res <- setDT(purrr::map2(fct, .SD, \(fn, args) purrr::exec(fn, args)))
setnames(res, paste(names(.SD), fct, sep = "_"))
}, by = date]
})
#user system elapsed
#134.966 1.530 136.620
# - fourth
system.time({
df1[, {
fct <- c("length", "mean")
res <- setDT(purrr::map2(fct, .SD, \(fn, args) purrr::exec(fn, args)))
setnames(res, paste(names(.SD), fct, sep = "_"))
}, .SDcols = 2:3, by = date]
})
#user system elapsed
#128.036 1.426 129.610
# - fifth
system.time({
df1[, {
fct <- c(N = "length", "mean")
res <- setDT(purrr::map2(fct, .SD, \(fn, args) purrr::exec(fn, args)))
given_names <- names(fct)
created_names <- paste(names(.SD), fct, sep = "_")
setnames(res,
if (is.null(given_names))
created_names
else
fifelse(given_names == "", created_names, given_names))
}, .SDcols = 2:3, by = date]
})
#user system elapsed
#131.960 1.552 133.595
-这篇文章的解决方案时间
# - akrun
# - first
system.time({
df1 %>%
group_by(date) %>%
summarise(user = n(), across(c(turnover, profit), sum))
})
#user system elapsed
#15.920 0.372 16.322
# - second
system.time({
collap(df1, ~ date, custom = list(fsum = c("turnover", "profit"),
fNobs = "turnover"))
})
#user system elapsed
#0.311 0.005 0.316