嵌套for循环的向量化
我有以下功能:嵌套for循环的向量化,r,vectorization,R,Vectorization,我有以下功能: g.Bn = function(n) { Bn = 0 for(k in 0:n) { res.of.loop = 0 for(j in 0:k) { res.of.loop = res.of.loop + (-1)^j * (j + 1)^n * choose(k, j) } Bn = res.of.loop * 1/(k+1) + Bn } return(Bn) } 这里有一种方法可以将其矢量化而不是使用for循环
g.Bn = function(n) {
Bn = 0
for(k in 0:n) {
res.of.loop = 0
for(j in 0:k) {
res.of.loop = res.of.loop + (-1)^j * (j + 1)^n * choose(k, j)
}
Bn = res.of.loop * 1/(k+1) + Bn
}
return(Bn)
}
这里有一种方法可以将其矢量化而不是使用for循环吗?您可以将for循环的
转换为map
和reduce
在下面的示例中,purrr::map
迭代所有数据,sum
将一个数值向量缩减为一个定标器(长度为1的数值向量)
似乎所有内环中的j
s都可以替换为0:k
g.Bn=函数(n){
总数(
映射dbl(0:n,函数(k){
求和(-1)^(0:k)*(0:k+1)^n*选择(k,0:k))*1/(k+1)
})
)
}
您可以矢量化内部循环(根据@DaveT),并使用sapply:
g.Bn2 = function(n) {
sum(sapply(0:n, function(k) {
sum((-1)^(0:k) * (0:k + 1)^n * choose(k, 0:k)) * 1/(k+1)
}))
}
或将外环矢量化的另一种可能性:
g.Bn3 = function(n) {
f <- function(k, n) sum((-1)^(0:k) * (0:k + 1)^n * choose(k, 0:k)) * 1/(k+1)
sum(Vectorize(f, vectorize.args = "k")(0:n, n))
}
您可以尝试用js替换内部循环。是否应该修改g.Bn
作为向量化函数?意思是当提供输入向量时返回答案向量的函数?@slava kohut也许我的问题不清楚。我想使用向量运算,但返回的值仍然应该是实数。哦,等等。可以用c实现。这很可能会大大提高速度。两个for
替换为两个purr::
。两者都在使用迭代。是什么让它更强大?我不是在批评。我问得很认真。使用purrr::
至少可以省去分配初始值设定项变量的麻烦。对我来说,通过使用嵌套匿名函数,每个级别上的逻辑都非常清晰。尝试了你的代码,在n
通过某个阈值后,g.Bn2
(g.Bn3
)会产生不同的结果。试试g.Bn(15)
和g.Bn2(15)
。为什么呢?老实说,我不确定,但我认为精确性是有原因的。我不能说哪种方法在这方面更好。我猜这可能与浮点运算有关。。。试着在原木上做吗?@waferthin谢谢你的回答。我发现,仅使用DaveT的方法处理内循环并保持外循环不变,就比您的任何解决方案都能获得更好的微基准结果。你认为这是为什么?sapply只是以类似于循环的方式进行迭代吗g.Bn=函数(n){Bn=0 for(k in 0:n){j=c(0:k)res.of.loop=sum(-1)^j*(j+1)^n*选择(k,j))Bn=Bn+res.of.loop*1/(k+1)}返回(Bn)
是的,通过内环的矢量化,可以实现此处的实际速度提高。所有其他更改实际上只是不同形式的循环(可以说语法更好,但没有真正的速度增益)。我认为加快速度的唯一办法是考虑是否可以以任何方式简化方程式。
g.Bn3 = function(n) {
f <- function(k, n) sum((-1)^(0:k) * (0:k + 1)^n * choose(k, 0:k)) * 1/(k+1)
sum(Vectorize(f, vectorize.args = "k")(0:n, n))
}
> microbenchmark(g.Bn(100), g.Bn2(100), g.Bn3(100))
expr min lq mean median uq max neval
g.Bn(100) 1493.086 1533.9280 1841.3455 1585.354 1675.3575 9023.316 100
g.Bn2(100) 617.063 650.7850 905.6899 738.230 788.7305 9224.460 100
g.Bn3(100) 685.094 772.3785 1015.9182 816.945 860.1775 8213.777 100