본문 바로가기

코드이야기/R

[R프로그래밍] 시뮬레이션의 기본 - 난수생성

 

동전이 하나 있다고 생각해 보겠습니다. 우리는 동전을 던지면 앞면과 뒷면이 나올 확률이 1/2이라는 것을 알고 있습니다. 그런데 앞면이 계속 나올 때도 있고 뒷면이 계속 나올 때도 있습니다. 동전을 무수히 많이 던지면 앞면과 뒷면이 나오는 횟수는 1/2에 근접해 갈 것입니다. 사진: glennharper

 

실제로 수없이 많이 동전을 던져 결과를 기록하는 것은 어려울지 모르지만 컴퓨터를 이용하면 쉽게 풀 수 있습니다. 이렇게 어떠한 현상이나 사건에 대한 모형을 만들어 가상으로 수행함으로써 실제 상황에 대한 결과를 예측하는 것을 시뮬레이션이라고 합니다.


동전을 던졌을 때 앞면이 나오는 것을 1, 뒷면이 나오는 것을 0라고 가정하겠습니다. 그럼 동전을 여러번 던지면 아래와 같은 수열을 얻을 수 있습니다.

1 0 1 0 0 1 1 1 0 0 1 1 0 1 0 1 ...

이런 수열을 난수열(random number sequence)이라고 합니다. 난수열은 두가지 성질을 가지고 있습니다. 등확률성과 무규칙성입니다. 등확률성은 일어나는 각각의 경우의 수가 같은 확률을 가졌다는 것을 의미하고, 무규칙성은 앞서 일어난 결과가 뒤의 결과에 영향을 미치지 않는다는 것을 의미합니다.


R을 이용해 이런 특성을 만족하는 난수를 생성해 보도록 하겠습니다. R을 이용해 난수를 생성하기 위해서는 runif()함수를 사용합니다. runif()함수의 용법은 아래와 같습니다.

runif(n, min, max)

여기서 n은 생성할 난수의 수, min, max는 난수의 범위를 나타냅니다. min, max를 생략하면, 0에서 1사이의 난수를 생성합니다.

[1] 0.9291576
> runif(1, 1, 2)
[1] 1.372035
> runif(1, 1, 3)
[1] 2.60515
> runif(10, 1, 3)
 [1] 2.756069 1.740509 1.647419 2.222761 1.841780 
 [6] 2.445014 2.368410 1.135294 1.840291 1.826523

R은 메르센 트위스터(Mersenne Twister)를 이용해 난수를 생성합니다. 메르센 트위스터는 1997년 마츠모토 마코토와 니시무라 다쿠지에 의해 개발된 의사난수(Pseudo-random number) 생성기입니다. 메르센 트위스터에 대한 자세한 내용은 위키피디아를 참고하세요.


이제 동전던지기의 난수를 생성해 보겠습니다. runif()함수가 기본적으로 0에서 1까지의 난수를 생성하므로 생성된 난수가 0.5보다 작으면 앞면(1), 그렇지 않으면 뒷면(0)이라고 정의하는 함수하나를 작성하겠습니다.

> coin <- function() {
+     x <- runif(1)
+     if (x <= 0.5) {
+         face <- 1
+     } else {
+         face <- 0
+     }
+     return(face)
+ }

> coin()
[1] 1
> coin()
[1] 0
> coin()
[1] 1
> coin()
[1] 0
> coin()
[1] 0

이제 간단한 난수 생성기가 만들어 졌습니다. 가위바위보는 세 가지의 경우의 수, 주사위는 여섯개의 면, 로또는 45개의 숫자로 이루어져 있다는 것을 이용해 다양한 난수를 생성할 수 있습니다.


그런데, 우리는 동전을 여러 번 던지고 그 확률을 계산해 보고싶습니다. 이 경우에는 위에서 작성한 함수를 활용해 새로운 함수를 작성할 수 있습니다.

> coins <- function(n) {
+     counter <- 0
+     for (i in 1:n) {
+         counter <- counter + coin()
+     }
+     return(counter/n)
+ }

> coins(10)
[1] 0.3
> coins(100)
[1] 0.51
> coins(1000)
[1] 0.512
> coins(10000)
[1] 0.5042
> coins(100000)
[1] 0.498
> coins(1000000)
[1] 0.499585

던지는 횟수가 늘어날 수록 확률은 0.5에 점점 근접해 가는 것을 확인할 수 있습니다. 다음 포스팅에서는 R을 이용해서 불확실한 상황하에서 의사결정에 유용하게 사용되는 몬테카를로 시뮬레이션을 구현해 보도록 하겠습니다.