我正在尝试在r中评估以下双和:
我知道outer
是一种快速的方法。我试过以下
sum(f(outer(X,X,function(x,y) (x-y)/c)))
虽然它似乎有效,但我不确定它与某些替代品相比有多快?首先是outer
然后我的功能,反之亦然,它在速度方面是否有所不同?有更好的方法吗?
答案 0 :(得分:3)
我想首先指出你可以把代码写成
sum(f(outer(x, x, "-") / c))
这减少了函数调用开销,因为R中的减法已经是一个函数。试试"-"(5, 2)
。
outer
对您的应用来说足够快。唯一不恰当的情况是当函数f
在0附近对称时,即f(-u) = f(u)
。在这种情况下,最优计算仅对组合矩阵outer(x, x, "-")
的下三角进行求和,并将该和乘以2以用于非对角线上的求和。最后,添加了对角线结果。
以下功能可以做到这一点。我们为组合矩阵的下三角部分(不包括对角线)生成(i, j)
索引,然后outer(x, x, "-") / c
的下三角部分将是dx <- (x[i] - x[j]) / c
。现在,
f
是对称的,则结果为2 * sum(f(dx)) + n * f(0)
,这比outer
快; f
不对称,我们必须执行sum(f(dx)) + sum(f(-dx)) + n * f(0)
,这对outer
没有任何优势。## `x` is the vector, `f` is your function of interest, `c` is a constant
## `symmetric` is a switch; only set `TRUE` when `f` is symmetric around 0
g <- function (x, f, c, symmetric = FALSE) {
n <- length(x)
j <- rep.int(1:(n-1), (n-1):1)
i <- sequence((n-1):1) + j
dx <- (x[i] - x[j]) / c
if (symmetric) 2 * sum(f(dx)) + n * f(0)
else sum(f(dx)) + sum(f(-dx)) + n * f(0)
}
在这里考虑一个小例子。我们假设c = 2
和向量x <- 1:500
。我们还考虑对称函数f1 <- cos
和非对称函数f2 <- sin
。让我们做一个基准:
x <- 1:500
library(microbenchmark)
我们首先考虑f1
的对称情况。请务必为symmetric = TRUE
设置g
。
microbenchmark(sum(f1(outer(x,x,"-")/2)), g(x, f1, 2, TRUE))
#Unit: milliseconds
# expr min lq mean median uq
# sum(f2(outer(x, x, "-")/2)) 32.79472 35.35316 46.91560 36.78152 37.63580
# g(x, f2, 2, TRUE) 20.24940 23.34324 29.97313 24.45638 25.33352
# max neval cld
# 133.5494 100 b
# 120.3278 100 a
我们在这里看到g
更快。
现在考虑使用f2
的非对称案例。
microbenchmark(sum(f2(outer(x,x,"-")/2)), g(x, f2, 2))
#Unit: milliseconds
# expr min lq mean median uq
# sum(f2(outer(x, x, "-")/2)) 32.84412 35.55520 44.33684 36.95336 37.89508
# g(x, f2, 2) 36.71572 39.11832 50.54516 40.25590 41.75060
# max neval cld
# 134.2991 100 a
# 142.5143 100 a
正如所料,这里没有优势。
是的,我们还想检查g
是否正在进行正确的计算。用x <- 1:5
来考虑一个小例子就足够了。
x <- 1:5
#### symmetric case ####
sum(f1(outer(x, x, "-") / 2))
# [1] 14.71313
g(x, f1, 2, TRUE)
# [1] 14.71313
#### asymmetric case ####
sum(f2(outer(x, x, "-") / 2))
# [1] 0
g(x, f2, 2)
# [1] 0
所以g
是正确的。