R 如何矢量化三重嵌套循环?
我已经搜索过类似的问题,我对应该做什么有一个模糊的想法:将所有内容矢量化或使用R 如何矢量化三重嵌套循环?,r,nested-loops,R,Nested Loops,我已经搜索过类似的问题,我对应该做什么有一个模糊的想法:将所有内容矢量化或使用apply()family。但是我是R编程的初学者,上面两种方法都很混乱 以下是我的源代码: x<-rlnorm(100,0,1.6) j=0 k=0 i=0 h=0 lambda<-rep(0,200) sum1<-rep(0,200) constjk=0 wj=0 wk=0 for (h in 1:200) { lambda[h]=2+h/12.5 N=ceiling(lambda[h
apply()
family。但是我是R编程的初学者,上面两种方法都很混乱
以下是我的源代码:
x<-rlnorm(100,0,1.6)
j=0
k=0
i=0
h=0
lambda<-rep(0,200)
sum1<-rep(0,200)
constjk=0
wj=0
wk=0
for (h in 1:200)
{
lambda[h]=2+h/12.5
N=ceiling(lambda[h]*max(x))
for (j in 0:N)
{
wj=(sum(x<=(j+1)/lambda[h])-sum(x<=j/lambda[h]))/100
for (k in 0:N)
{
constjk=dbinom(k, j + k, 0.5)
wk=(sum(x<=(k+1)/lambda[h])-sum(x<=k/lambda[h]))/100
sum1[h]=sum1[h]+(lambda[h]/2)*constjk*wk*wj
}
}
}
x您的代码可以通过3个嵌套的sapply
调用进行完美的校正。对于未经训练的人来说,这可能有点难理解,但其本质是,我们不是一次向sum1[h]
添加一个值,而是一次计算最内部循环产生的所有项,并将它们相加
尽管此矢量化解决方案比Triplefor
循环更快,但改进并不显著。如果您计划多次使用它,我建议您使用C或Fortran实现它(对于
循环使用常规的),这将大大提高速度。但要注意,它的时间复杂度很高,并且会随着lambda
值的增加而严重扩展,最终达到无法在合理时间内进行计算的程度,无论实现如何
lambda <- 2 + 1:200/12.5
sum1 <- sapply(lambda, function(l){
N <- ceiling(l*max(x))
sum(sapply(0:N, function(j){
wj <- (sum(x <= (j+1)/l) - sum(x <= j/l))/100
sum(sapply(0:N, function(k){
constjk <- dbinom(k, j + k, 0.5)
wk <- (sum(x <= (k+1)/l) - sum(x <= k/l))/100
l/2*constjk*wk*wj
}))
}))
})
lambda让我们将模拟包装在函数中并计时:
sim1 <- function(num=20){
set.seed(42)
x<-rlnorm(100,0,1.6)
j=0
k=0
i=0
h=0
lambda<-rep(0,num)
sum1<-rep(0,num)
constjk=0
wj=0
wk=0
for (h in 1:num)
{
lambda[h]=2+h/12.5
N=ceiling(lambda[h]*max(x))
for (j in 0:N)
{
wj=(sum(x<=(j+1)/lambda[h])-sum(x<=j/lambda[h]))/100
for (k in 0:N)
{
set.seed(42)
constjk=dbinom(k, j + k, 0.5)
wk=(sum(x<=(k+1)/lambda[h])-sum(x<=k/lambda[h]))/100
sum1[h]=sum1[h]+(lambda[h]/2)*constjk*wk*wj
}
}
}
sum1
}
system.time(res1 <- sim1())
# user system elapsed
# 5.4 0.0 5.4
如果这仍然太慢,并且您不能或不想使用另一种语言,那么也有并行化的可能性。就我所见,外环是令人尴尬的平行。有一些很好且简单的并行化包 这是第一个,基本上我想计算两个EDF之间的差值,因此/100.lambda和N值可以在循环外使用vector命令计算。这里就是这样。在N和λ值已知的情况下,您可能可以在此之后加速wj计算,但不会太快。(wj可以是循环外的两个小的的sapply
,仅用于求和(xIn-general,遵循以下规则:如果第j次计算取决于(j-1)的结果)计算,然后你不能矢量化。如果没有,你可以。如果你有时间尝试C++实现……如果你在C++中足够流畅。谢谢!我认为它已经足够快了(实际上我发现它在实验室的计算机上运行得比我的笔记本电脑快得多,这是个好兆头,因为我现在不需要改变很多代码)。。非常感谢!这非常有帮助,因为现在我可以慢慢地将所有其他代码转换为sapply()。
sim2 <- function(num=20){
set.seed(42) #to make it reproducible
x <- rlnorm(100,0,1.6)
h <- 1:num
sum1 <- numeric(num)
lambda <- 2+1:num/12.5
N <- ceiling(lambda*max(x))
#functions for wj and wk
wjfun <- function(x,j,lambda,h){
(sum(x<=(j+1)/lambda[h])-sum(x<=j/lambda[h]))/100
}
wkfun <- function(x,k,lambda,h){
(sum(x<=(k+1)/lambda[h])-sum(x<=k/lambda[h]))/100
}
#function to calculate values of sum1
fun1 <- function(N,h,x,lambda) {
sum1 <- 0
set.seed(42) #to make it reproducible
#calculate constants using outer
const <- outer(0:N[h],0:N[h],FUN=function(j,k) dbinom(k, j + k, 0.5))
wk <- numeric(N[h]+1)
#loop only once to calculate wk
for (k in 0:N[h]){
wk[k+1] <- (sum(x<=(k+1)/lambda[h])-sum(x<=k/lambda[h]))/100
}
for (j in 0:N[h])
{
wj <- (sum(x<=(j+1)/lambda[h])-sum(x<=j/lambda[h]))/100
for (k in 0:N[h])
{
sum1 <- sum1+(lambda[h]/2)*const[j+1,k+1]*wk[k+1]*wj
}
}
sum1
}
for (h in 1:num)
{
sum1[h] <- fun1(N,h,x,lambda)
}
sum1
}
system.time(res2 <- sim2())
#user system elapsed
#1.25 0.00 1.25
all.equal(res1,res2)
#[1] TRUE
user system elapsed
3.30 0.00 3.29