함수에서 먼저 코드를 마무리합시다. 또한 결과를 재현 가능하게하기 위해 set.seed
명령을 추가했습니다. 시뮬레이션을 실행하기 전에 제거해야합니다. result
O를 통해 각각의 반복 동안 덮어 것을
는
sim1 <- function(reps=50, steps=100) {
N<-5 # number of sites
sites<-LETTERS[seq(from=1,to=N)]
to.r<-rbind(sites)
p.move.r<-seq.int(0.05,0.90,by=0.05) # prob of moving to a new site
p.leave<-0.01*p.move.r # prob of leaving the system w/out returning
p.move.out<-0.01*p.move.r # prob of moving in/out
p.stay<-1-(p.move.r+p.leave+p.move.out) # prob of staying in the same site
set.seed(42)
random<-runif(10000,0,1) # generating numbers from a random distribution
cumsum.move <- read.table(text="A B C D E NA. left
A 0.0820000 0.3407822 0.6392209 0.3516242 0.3925942 0.1964 0.1964
B 0.1254937 0.4227822 0.6940040 0.3883348 0.4196630 0.3928 0.3928
C 0.7959865 0.8730183 0.7760040 0.7930623 0.8765180 0.5892 0.5892
D 0.8265574 0.8980259 0.8095507 0.8750623 0.9000000 0.7856 0.7856
E 0.9820000 0.9820000 0.9820000 0.9820000 0.9820000 0.9820 0.9820
NA. 0.9910000 0.9910000 0.9910000 0.9910000 0.9910000 0.9910 0.9910
left 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000 1.0000",header=TRUE)
cumsum.move <- as.matrix(cumsum.move)
for(o in 1:reps){
result<-matrix(as.character(""),steps) # Vector for storing sites
set.seed(42)
x<-sample(random,steps,replace=TRUE) # sample array of random number
time.step<-data.frame(x) # time steps used in the simulation (i)
colnames(time.step)<-c("time.step")
time.step$event<-""
set.seed(41)
j<-sample(1:N,1,replace=T) # first column to be selected
set.seed(40)
k<-sample(1:N,1,replace=T) # selection of column for ind. that move in/out
for(i in 1:steps){
for (t in 1:(N+1)){
if(time.step$time.step[i]<cumsum.move[t,j]){
time.step$event[i]<-to.r[t]
break
}
}
ifelse(time.step$event[i]=="",break,NA)
result[i]<-time.step$event[i]
j<-which(to.r==result[i])
if(length(j)==0){j<-k}
}
result<-time.step$event
}
result
}
참고. 네가 그렇게하기를 원하지 않는다고 생각 했어. 또한 루프 내에 data.frame
을 사용합니다. 일반적으로 전염병처럼 루프 안에 data.frames
을 피해야합니다. 그들은 매우 편리하지만 효율면에서 끔찍합니다.
sim2 <- function(reps=50, steps=100) {
N<-5 # number of sites
sites<-LETTERS[seq(from=1,to=N)]
to.r<-rbind(sites)
p.move.r<-seq.int(0.05,0.90,by=0.05) # prob of moving to a new site
p.leave<-0.01*p.move.r # prob of leaving the system w/out returning
p.move.out<-0.01*p.move.r # prob of moving in/out
p.stay<-1-(p.move.r+p.leave+p.move.out) # prob of staying in the same site
set.seed(42)
random<-runif(10000,0,1) # generating numbers from a random distribution
cumsum.move <- read.table(text="A B C D E NA. left
A 0.0820000 0.3407822 0.6392209 0.3516242 0.3925942 0.1964 0.1964
B 0.1254937 0.4227822 0.6940040 0.3883348 0.4196630 0.3928 0.3928
C 0.7959865 0.8730183 0.7760040 0.7930623 0.8765180 0.5892 0.5892
D 0.8265574 0.8980259 0.8095507 0.8750623 0.9000000 0.7856 0.7856
E 0.9820000 0.9820000 0.9820000 0.9820000 0.9820000 0.9820 0.9820
NA. 0.9910000 0.9910000 0.9910000 0.9910000 0.9910000 0.9910 0.9910
left 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000 1.0000",header=TRUE)
cumsum.move <- as.matrix(cumsum.move)
res <- list()
for(o in 1:reps){
result<-character(steps) # Vector for storing sites
set.seed(42)
time.step<-sample(random,steps,replace=TRUE) # sample array of random number
#time.step<-data.frame(x) # time steps used in the simulation (i)
#colnames(time.step)<-c("time.step")
#time.step$event<-""
event <- character(steps)
set.seed(41)
j<-sample(1:N,1,replace=T) # first column to be selected
set.seed(40)
k<-sample(1:N,1,replace=T) # selection of column for ind. that move in/out
for(i in 1:steps){
for (t in 1:(N+1)){
if(time.step[i]<cumsum.move[t,j]){
event[i]<-to.r[t]
break
}
}
ifelse(event[i]=="",break,NA)
result[i]<-event[i]
j<-which(to.r==result[i])
if(length(j)==0){j<-k}
}
res[[o]]<-event
}
do.call("rbind",res)
}
두 기능 모두 동일한 결과를 제공합니까?
res1 <- sim1()
res2 <- sim2()
all.equal(res1,res2[1,])
[1] TRUE
새 버전이 더 빠릅니까?
library(microbenchmark)
microbenchmark(sim1(),sim2())
Unit: milliseconds
expr min lq median uq max
1 sim1() 204.46339 206.58508 208.38035 212.93363 269.41693
2 sim2() 77.55247 78.39698 79.30539 81.73413 86.84398
글쎄요, 3 인자는 이미 아주 좋습니다. 루프를 더 향상시킬 수있는 가능성은별로 없습니다. break
입니다. 따라서 병렬 처리 만 옵션으로 남겨 둡니다.
sim3 <- function(ncore=1,reps=50, steps=100) {
require(foreach)
require(doParallel)
N<-5 # number of sites
sites<-LETTERS[seq(from=1,to=N)]
to.r<-rbind(sites)
p.move.r<-seq.int(0.05,0.90,by=0.05) # prob of moving to a new site
p.leave<-0.01*p.move.r # prob of leaving the system w/out returning
p.move.out<-0.01*p.move.r # prob of moving in/out
p.stay<-1-(p.move.r+p.leave+p.move.out) # prob of staying in the same site
set.seed(42)
random<-runif(10000,0,1) # generating numbers from a random distribution
cumsum.move <- read.table(text="A B C D E NA. left
A 0.0820000 0.3407822 0.6392209 0.3516242 0.3925942 0.1964 0.1964
B 0.1254937 0.4227822 0.6940040 0.3883348 0.4196630 0.3928 0.3928
C 0.7959865 0.8730183 0.7760040 0.7930623 0.8765180 0.5892 0.5892
D 0.8265574 0.8980259 0.8095507 0.8750623 0.9000000 0.7856 0.7856
E 0.9820000 0.9820000 0.9820000 0.9820000 0.9820000 0.9820 0.9820
NA. 0.9910000 0.9910000 0.9910000 0.9910000 0.9910000 0.9910 0.9910
left 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 1.0000 1.0000",header=TRUE)
cumsum.move <- as.matrix(cumsum.move)
#res <- list()
#for(o in 1:reps){
cl <- makeCluster(ncore)
registerDoParallel(cl)
res <- foreach(1:reps) %dopar% {
result<-character(steps) # Vector for storing sites
set.seed(42)
time.step<-sample(random,steps,replace=TRUE) # sample array of random number
#time.step<-data.frame(x) # time steps used in the simulation (i)
#colnames(time.step)<-c("time.step")
#time.step$event<-""
event <- character(steps)
set.seed(41)
j<-sample(1:N,1,replace=T) # first column to be selected
set.seed(40)
k<-sample(1:N,1,replace=T) # selection of column for ind. that move in/out
for(i in 1:steps){
for (t in 1:(N+1)){
if(time.step[i]<cumsum.move[t,j]){
event[i]<-to.r[t]
break
}
}
ifelse(event[i]=="",break,NA)
result[i]<-event[i]
j<-which(to.r==result[i])
if(length(j)==0){j<-k}
}
#res[[o]]<-event
event
}
stopCluster(cl)
do.call("rbind",res)
}
같은 결과가 있습니까?
res3 <- sim3()
all.equal(res1,c(res3[1,]))
[1] TRUE
더 빠름? (의 내 Mac에서 4 개 코어를 사용하자. 당신은 몇 가지 더 코어 서버에 접근을 시도 할 수도 있습니다.) 끔찍
microbenchmark(sim1(),sim2(),sim3(4))
Unit: milliseconds
expr min lq median uq max
1 sim1() 202.28200 207.64932 210.32582 212.69869 255.2732
2 sim2() 75.39295 78.95882 80.01607 81.49027 125.0866
3 sim3(4) 1031.02755 1046.41610 1052.72710 1061.74057 1091.2175
합니다. 그러나이 테스트는 병렬 기능에 불공평합니다. 이 함수는 50 회 반복만으로 100 회 호출됩니다. 즉, 병렬화의 오버 헤드가 발생하지만 거의 이점이 없습니다. 이제 더 공정한 만들어 보자 : 여전히
microbenchmark(sim1(rep=10000),sim2(rep=10000),sim3(ncore=4,rep=10000),times=1)
Unit: seconds
expr min lq median uq max
1 sim1(rep = 10000) 42.16821 42.16821 42.16821 42.16821 42.16821
2 sim2(rep = 10000) 16.13822 16.13822 16.13822 16.13822 16.13822
3 sim3(ncore = 4, rep = 10000) 38.18873 38.18873 38.18873 38.18873 38.18873
더 나은,하지만 인상적 없습니다. 반복 횟수와 단계 수가 추가로 증가하면 병행 함수가 좋아 보이지만 필요한지 여부는 알 수 없습니다.
고마워 롤랜드, 실제로 사용하고있는 코드의 좀 더 자세한/재현성있는 예제를 포함하기 위해 원래 코드를 일부 편집했습니다 (또한 몇 가지 추가 루프가 있음 ...). 먼저 스크립트를 점검 할 것입니다. 귀하의 의견을 보내 주셔서 감사합니다! – user1626688
안녕하세요 롤랜드,이 코드가 더 자세한 편집을 포함 할 때 유용할지 모르겠습니다 ... 각 매개 변수에 대한 시뮬레이션을 실행해야하기 때문입니다. – user1626688
새로운 코드를 비슷한 방식으로 최적화 할 수 있다고 확신합니다. 요점은 효율적인 데이터 구조 (벡터 또는 목록)를 사용하여 값을 저장하는 것입니다. 'Rprof' 함수를 사용하여 가장 많은 시간이 걸리는 작업을 찾고 해당 코드를 최적화하십시오. 가능할 때마다 벡터화 된 함수를 사용하십시오. 병렬 처리를 살펴보십시오. – Roland