Ana*_*and 7 benchmarking r tapply
该by函数是否生成一次只增长一个元素的列表?
我需要处理一个数据框,其中大约有4M观测值按因子列分组.情况类似于以下示例:
> # Make 4M rows of data
> x = data.frame(col1=1:4000000, col2=10000001:14000000)
> # Make a factor
> x[,"f"] = x[,"col1"] - x[,"col1"] %% 5
>
> head(x)
col1 col2 f
1 1 10000001 0
2 2 10000002 0
3 3 10000003 0
4 4 10000004 0
5 5 10000005 5
6 6 10000006 5
Run Code Online (Sandbox Code Playgroud)
现在,tapply其中一个列需要一段合理的时间:
> t1 = Sys.time()
> z = tapply(x[, 1], x[, "f"], mean)
> Sys.time() - t1
Time difference of 22.14491 secs
Run Code Online (Sandbox Code Playgroud)
但如果我这样做:
z = by(x[, 1], x[, "f"], mean)
Run Code Online (Sandbox Code Playgroud)
几乎没有在同一时间完成(我在一分钟后放弃了).
当然,在上面的例子中,tapply可以使用,但实际上我需要一起处理多个列.有什么更好的方法呢?
by比它慢,tapply因为它正在包装by。让我们看一下一些基准:tapply在这种情况下比使用快 3 倍以上by
已更新以包括@Roland 的精彩推荐:
library(rbenchmark)
library(data.table)
dt <- data.table(x,key="f")
using.tapply <- quote(tapply(x[, 1], x[, "f"], mean))
using.by <- quote(by(x[, 1], x[, "f"], mean))
using.dtable <- quote(dt[,mean(col1),by=key(dt)])
times <- benchmark(using.tapply, using.dtable, using.by, replications=10, order="relative")
times[,c("test", "elapsed", "relative")]
#------------------------#
# RESULTS #
#------------------------#
# COMPARING tapply VS by #
#-----------------------------------
# test elapsed relative
# 1 using.tapply 2.453 1.000
# 2 using.by 8.889 3.624
# COMPARING data.table VS tapply VS by #
#------------------------------------------#
# test elapsed relative
# 2 using.dtable 0.168 1.000
# 1 using.tapply 2.396 14.262
# 3 using.by 8.566 50.988
Run Code Online (Sandbox Code Playgroud)
不过,请注意,它们相对于非因子输入都有所改善,而 data.table 保持大致相同或更差
x[, "f"] <- as.factor(x[, "f"])
dt <- data.table(x,key="f")
times <- benchmark(using.tapply, using.dtable, using.by, replications=10, order="relative")
times[,c("test", "elapsed", "relative")]
# test elapsed relative
# 2 using.dtable 0.175 1.000
# 1 using.tapply 1.803 10.303
# 3 using.by 7.854 44.880
Run Code Online (Sandbox Code Playgroud)
?by:描述
Function by 是应用于数据帧的 Tapply 的面向对象包装器。
让我们看一下by(或更具体地说,by.data.frame)的来源:
by.data.frame
function (data, INDICES, FUN, ..., simplify = TRUE)
{
if (!is.list(INDICES)) {
IND <- vector("list", 1L)
IND[[1L]] <- INDICES
names(IND) <- deparse(substitute(INDICES))[1L]
}
else IND <- INDICES
FUNx <- function(x) FUN(data[x, , drop = FALSE], ...)
nd <- nrow(data)
ans <- eval(substitute(tapply(seq_len(nd), IND, FUNx, simplify = simplify)),
data)
attr(ans, "call") <- match.call()
class(ans) <- "by"
ans
}
Run Code Online (Sandbox Code Playgroud)
我们立即看到仍然有一个调用tapply加上很多额外的内容(包括调用deparse(substitute(.))和 aneval(substitute(.))两者都相对较慢)。tapply因此,您的速度比类似的调用相对更快是有道理的by。
| 归档时间: |
|
| 查看次数: |
173 次 |
| 最近记录: |