doRNG 패키지로 foreach를 재현가능하도록 사용하기
R에서 for 문의 느린 속도를 개선하기 위해 가장 많이 사용하는 방법 중 하나가 doParallel 패키지의 foreach()
를 통해 병렬로 연산하는 것인데요.
하지만 seed를 설정하여 이후 같은 결과를 얻게 하는 재현성(reproducibility)을 위해서 foreach()
를 사용할 때에는 주의할 필요가 있습니다.
보통 seed를 설정할 때 사용하는 set.seed()
가 제대로 적용되지 않기 때문이죠.
다음의 예제를 확인해볼까요? (본문에서 사용한 예제 코드는 doRNG 패키지의 RDocument를 참고하였습니다.)
각 반복마다 \(Uniform(0,1)\)에서 sample 1개씩을 뽑는 과정을 foreach()
함수를 사용한 예제입니다.
그리고 재현성을 위해 set.seed(1234)
를 설정해주었습니다.
library(doParallel)
cl <- makeCluster(2)
registerDoParallel(cl)
# foreach에서 %dopar% 구문으로 생성
set.seed(1234)
s1 <- foreach(i = 1:4) %dopar% {
runif(1)
}
set.seed(1234)
s2 <- foreach(i = 1:4) %dopar% {
runif(1)
}
# 두 벡터가 같은지 비교
identical(s1, s2)
## [1] FALSE
하지만 예상과 달리 seed를 지정해주었음에도 runif()
에서 뽑힌 값이 다른 것을 확인할 수 있습니다. (정확한 이유는 잘 모르겠습니다. . .)
그렇다면 이 문제는 어떻게 해결할 수 있을까요?
바로 doRNG 패키지를 사용하면 됩니다!!!
doRNG 패키지
앞에서의 문제는 doRNG 패키지 내의 %dorng%
또는 registerDoRNG()
를 활용하여 해결할 수 있으며, 이제 두 방법을 하나씩 살펴보겠습니다.
1. %dorng% + .options.RNG
첫 번째 방법은 %dopar%
대신 %dorng%
를 사용하는 것인데요.
이와 더불어 .options.RNG
옵션으로 seed를 설정해주어야 합니다.
다음에서 사용법과 간단한 예제를 확인해보겠습니다.
다음은 %dorng% + .options.RNG = 1234
가 같은 값을 생성하는지 비교하는 예제입니다.
# 패키지 load
library(doRNG)
# %dorng% 구문으로 생성
r1 <- foreach(i = 1:4, .options.RNG = 1234) %dorng% {
runif(1)
}
r2 <- foreach(i = 1:4, .options.RNG = 1234) %dorng% {
runif(1)
}
# 두 벡터가 같은지 비교
identical(r1, r2)
## [1] TRUE
set.seed()
를 사용했을 때와 달리 %dorng% + .options.RNG
를 적용하여 생성된 두 벡터가 같은 것을 확인할 수 있습니다.
2. registerDoRNG
두 번째 방법은 registerDoRNG()
함수를 사용하여 seed를 설정하는 것입니다.
set.seed()
와 마찬가지로 함수 argument로 seed를 설정해주면 됩니다.
다음은 같은 seed로 %dorng% + .options.RNG
와 registerDoRNG()
가 같은 값을 생성하는지 비교하는 예제입니다.
# registerDoRNG로 seed 설정
registerDoRNG(1234)
r1 <- foreach(i = 1:4) %dopar% {
runif(1)
}
# %dorng% 구문으로 seed 설정
r2 <- foreach(i = 1:4, .options.RNG = 1234) %dorng% {
runif(1)
}
# 두 벡터가 같은지 비교
identical(r1, r2)
## [1] TRUE
사용하는 방법이 약간 다르지만, 두 방법에서 생성된 벡터가 서로 같다는 것을 확인할 수 있습니다.