简体   繁体   English

通过R中的唯一值进行更有效的循环

[英]More efficient loops thru unique values in R

I am relatively new to R and all its wisdom and I am trying to be more efficient with my script. 我对R及其所有才智相对较新,我正在尝试提高脚本的效率。 I am using a loop to simulate how an animal moves among different sites. 我正在使用一个循环来模拟动物如何在不同位置之间移动。 The problem that I have is that when I increase the number of sites or change the initial parameters (based on fixed probability of moving or staying in the same site) then I end with a very complicated loop. 我的问题是,当我增加站点数量或更改初始参数(基于移动或停留在同一站点的固定概率)时,我将遇到一个非常复杂的循环。 If I have to run several different simulations with different parameters, I prefer a more efficient loop or function that could adjust to different situations. 如果必须使用不同的参数运行多个不同的仿真,则我更喜欢可以根据不同情况进行调整的更有效的循环或函数。 The first loop will fill a matrix according to the initial probabilities and the second loop will compared the cumulative probability matrix against a random number from a list of values (10 in this example) and will decide the fate of that individual (either stay or go to a new site) 第一个循环将根据初始概率填充矩阵,第二个循环将比较累积概率矩阵与值列表中的随机数(在此示例中为10),并确定该人的命运(留下或走出去)到新站点)

Here is a simplification of my code: 这是我的代码的简化:

N<-4 # number of sites
sites<-LETTERS[seq(from=1,to=N)]

p.stay<-0.45
p.move<-0.4

move<-matrix(c(0),nrow=N,ncol=N,dimnames=list(c(sites),c(sites)))
from<-array(0,c(N,N),dimnames=list(c(sites),c(sites)))
to<-array(0,c(N,N),dimnames=list(c(sites),c(sites)))

# Filling matrix with fixed probability # #以固定概率填充矩阵#

for(from in 1:N){
  for(to in 1:N){
     if(from==to){move[from,to]<-p.stay} else {move[from,to]<-p.move/(N-1)}
     }
 }

move
cumsum.move<-cumsum(data.frame(move))

steps<-100
result<-as.character("") # for storing results
rand<-sample(random,steps,replace=TRUE) 
time.step<-data.frame(rand)
colnames(time.step)<-c("time.step")
time.step$event<-""
to.r<-(rbind(sites))
j<-sample(1:N,1,replace=T) # first column to select (random number)
k<-sample(1:N,1,replace=T) # site selected after leaving and coming back

# Beginning of the longer loop # #更长循环的开始#

for(i in 1:steps){
   if (time.step$time.step[i]<cumsum.move[1,j]){time.step$event[i]<-to.r[1]} else 
     if (time.step$time.step[i]<cumsum.move[2,j]){time.step$event[i]<-to.r[2]} else
        if (time.step$time.step[i]<cumsum.move[3,j]){time.step$event[i]<-to.r[3]} else
           if (time.step$time.step[i]<cumsum.move[4,j]){time.step$event[i]<-to.r[4]} else
              if (time.step$time.step[i]<(0.95)){time.step$event[i]<-NA} else
                 if (time.step$time.step[i]<1.0) break # break the loop             

 result[i]<-time.step$event[i]
 j<-which(to.r==result[i])
 if(length(j)==0){j<-k} # for individuals the leave and come back later

 }

 time.step

 result

This loop is part of a bigger loop that will simulate and store the result after a series of simulations. 该循环是更大循环的一部分,该循环将在一系列模拟之后模拟并存储结果。 Any ideas or comments on how I can improve the efficiency of this loop so that I can easily modify the number of sites or change the initial probability parameters without repeating or having to do major edits of the loop will be appreciated. 任何有关如何提高此循环效率的想法或意见,使我可以轻松地修改站点数或更改初始概率参数,而无需重复或不必对循环进行主要编辑。

I'm not sure if I'm capturing the essence of your code, but this is faster than the for loops. 我不确定是否要捕获代码的本质,但这比for循环要快。 This started having an advantage as soon as we start getting past a few thousand steps. 一旦我们开始经过几千步,这便开始具有优势。 I replace "random" with a sample of the uniform distribution ( runif() ) 我用均匀分布的样本( runif() )替换了“ random”

system.time(
time.step$event <- sapply(
  time.step$time.step, 
  function(x) rownames(
    cumsum.move[which(cumsum.move[,j] > x),])[[1]]
  )
)

Here are my results @ 10,000 steps. 这是我的结果@ 10,000步。 I'm working on a laptop so 100,000 with the for loop didn't compute in under 1 minute, but sapply did it in 14 seconds. 我正在使用笔记本电脑,因此10万个带有for循环的代码无法在1分钟内计算出来,但是sapply在14秒内就完成了计算。

> system.time(
+ time.step$event <- sapply(
+ time.step$time.step,
+ function(x) rownames(
+ cumsum.move[which(cumsum.move[,j] > x),])[[1]]
+ )
+ )
   user  system elapsed 
  1.384   0.000   1.387 
> head(time.step)
  time.step event
1 0.2787642     C
2 0.3098240     C
3 0.9079045     D
4 0.9904031     D
5 0.3754330     C
6 0.6984415     C
> system.time(
+ for(i in 1:steps){
+ if (time.step$time.step[i]<cumsum.move[1,j]){time.step$event[i]<-to.r[1]} else
+ if (time.step$time.step[i]<cumsum.move[2,j]){time.step$event[i]<-to.r[2]} else
+ if (time.step$time.step[i]<cumsum.move[3,j]){time.step$event[i]<-to.r[3]} else
+ if (time.step$time.step[i]<cumsum.move[4,j]){time.step$event[i]<-to.r[4]}
+ result[i]<-time.step$event[i]
+ }
+ )
   user  system elapsed 
  3.137   0.000   3.143 
> head(time.step)
  time.step event
1 0.2787642     C
2 0.3098240     C
3 0.9079045     D
4 0.9904031     D
5 0.3754330     C
6 0.6984415     C

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM