IDL/Math

RANDOMU 함수를 사용한 난수 생성 (Part 2)

이상우_IDL 2016. 8. 1. 15:35
728x90

* 이전 게시물에서 계속 이어집니다.


이전 게시물에서는 RANDOMU 함수를 사용하여 1000개의 난수값들을 생성하고 이 값들이 균일 분포(Uniform Distribution)를 따른다는 내용까지 언급하였습니다. 그런데 RANDOMU 함수로 다른 형태의 분포를 따르는 난수값들을 생성하는 것도 가능합니다. 만약 다음과 같이 NORMAL 키워드를 사용하면 정규 분포(Normal Distribution)를 따르는 난수값들을 생성할 수 있습니다.


IDL> data = RANDOMU(seed, 1000, /NORMAL)

IDL> PRINT, MIN(data), MAX(data)

     -3.63502      3.54361

IDL> PRINT, MEAN(data)

 -0.000904566


그런데 위의 출력결과들을 보면, 생성된 난수값들의 분포와 관련된 정보들을 확인할 수 있는데요. 정확히 얘기하면, 평균이 0이고 표준편차가 1인 정규 분포를 따르는 난수값들로 생성됩니다. 만약 다음과 같이 약간의 연산을 추가하여 내가 원하는 범위 또는 편차를 갖는 값들을 생성하는 것도 가능합니다.


IDL> data = RANDOMU(seed, 1000, /NORMAL)*10+50

IDL> PRINT, MIN(data), MAX(data)

      18.8220      77.3768

IDL> PRINT, MEAN(data)

      49.9493


이 경우 평균이 50이고 표준편차가 10인 분포를 따르는 난수들을 생성할 수 있습니다. 이와 같은 방식으로 난수를 생성하여, 이전 게시물에서와 같은 방식으로 히스토그램을 그려봅시다.


data = RANDOMU(seed, 1000, /NORMAL)*10+50 & str = 'Normal Distribution'

HELP, data

PRINT, MIN(data), MAX(data)

bsz = 1

hist = HISTOGRAM(data, MIN=0, MAX=100, BINSIZE=bsz, LOCATIONS=xh)

win = WINDOW(DIMENSIONS=[600, 500])

pl = BARPLOT(xh+bsz/2., hist, XRANGE=[0, 100], YRANGE=[0, 50], $

  YMINOR=0, YTICKLEN=0, FILL_COLOR='green', TITLE=str, $

  XTITLE='Value', YTITLE='Count', /CURRENT)


이와 같은 코드를 실행하면 그 결과는 다음 그림과 같습니다. 히스토그램을 그리기 위하여 HISTOGRAM 함수로 분포 데이터를 얻는데 있어서는 0부터 100까지의 범위 내에서 폭이 1인 세부 구간별 빈도수를 구하도록 하였습니다. 예상했던 대로 전형적인 정규 분포의 형태를 보여주는 것을 확인할 수 있습니다.


그리고 RANDOMU 함수에서는 포아송(Poisson) 분포를 따르는 난수들의 생성도 가능합니다. 이 분포는 단위 시간 안에 어떤 사건이 몇 번 발생할 것인가를 나타내는 것입니다. 예를 들어 기대값이 50이라고 하면, 단위 시간 안에 발생하는 실제 사건 발생 횟수는 대략 50을 전후한 값이 될텐데, 이 값을 산출하는 식(검색해보면 나옵니다)은 따로 있습니다. 어쨌든 이와 같은 포아송 분포 기반의 난수를 얻으려면 다음과 같이 POISSON 키워드에 기대값을 부여하면 됩니다. 여기서는 기대값을 50인 포아송 분포를 기반으로 한 1000개의 난수들을 생성하여 그 분포도를 그려보았습니다.


data = RANDOMU(seed, 1000, POISSON=50) & str = 'Poisson Distribution'

HELP, seed

HELP, data

PRINT, MIN(data), MAX(data)

bsz = 1

hist = HISTOGRAM(data, MIN=0, MAX=100, BINSIZE=bsz, LOCATIONS=xh)

win = WINDOW(DIMENSIONS=[600, 500])

pl = BARPLOT(xh+bsz/2., hist, XRANGE=[0, 100], YRANGE=[0, 80], $

  YMINOR=0, YTICKLEN=0, FILL_COLOR='dodger blue', TITLE=str, $

  XTITLE='Value', YTITLE='Count', /CURRENT)


이와 같은 코드를 실행하면 그 결과는 다음 그림과 같습니다. 얼핏 보면 정규 분포와 비슷해 보일 수도 있지만, 정규 분포와 포아송 분포는 엄연히 다릅니다.



RANDOMU 함수에서는 그 외에도 이항(Binomial) 분포 기반의 난수 생성도 가능합니다. 이것은 n번의 독립적 시행에서 각 시행이 확률 p를 가질 경우의 이산 확률 분포라고 볼 수 있습니다. 예를 들어 주사위를 30회 던져서 6이란 숫자를 얻는 횟수를 센다면, 이 경우는 n이 30이고 p가 1/6인 이항분포가 됩니다. 이러한 분포를 기반으로 한 난수 1000개를 생성하려면 다음과 같이 BINOMIAL 키워드에 이 두 값으로 이루어진 배열을 인수로 넣으면 됩니다. 이렇게 이항 분포 기반의 난수를 생성하고 그 분포도를 그리는 코드는 다음과 같습니다.


data = RANDOMU(seed, 1000, BINOMIAL=[30, 1./6]) & str = 'Binomial Distribution'

HELP, seed

HELP, data

PRINT, MIN(data), MAX(data)

bsz = 1

hist = HISTOGRAM(data, MIN=0, MAX=20, BINSIZE=bsz, LOCATIONS=xh)

win = WINDOW(DIMENSIONS=[600, 500])

pl = BARPLOT(xh+bsz/2., hist, XRANGE=[0, 20], YRANGE=[0, 250], $

  YMINOR=0, YTICKLEN=0, FILL_COLOR='violet', TITLE=str, $

  XTITLE='Value', YTITLE='Count', /CURRENT)


이 코드를 실행하면 그 결과는 다음 그림과 같습니다. 이 그림의 의미는 주사위를 30회 던져서 6이란 숫자를 얻는 횟수가 30/6=5가 될 가능성이 높다는 것입니다. 물론, 이러한 시도 자체를 1000번 수행하면 그 횟수는 5나 4가 될 가능성이 가장 높긴 하지만, 그 주변값들이 될 가능성도 어느 정도 존재한다는 의미로 보면 됩니다.



지금까지 RANDOMU 함수의 다양한 사용 예제들을 살펴보았습니다. 다양한 분포를 기반으로 한 난수들의 생성이 가능하다는 점을 주목해둘 필요가 있겠습니다. 위의 예제들에서는 많은 수의 난수들을 생성하여 그 분포를 살펴보는 것이 주안점을 두었지만, 좀 더 단순한 방식의 활용도 가능합니다. 예를 들어, 점심 식사를 하러 가는데 일행이 나까지 총 7명이 있는 상태에서, 누구 한 사람이 점심값을 쏘는 내기를 할 경우를 생각해보면 그 대상자는 다음과 같이 추첨할 수도 있습니다.


IDL> PRINT, ROUND(RANDOMU(seed, 1)*6+1)

           5


여기서는 먼저 RANDOMU 함수로 난수 하나를 생성하면 그 자체는 0~1 범위의 실수인데, 여기에 6을 곱하면 0~6 범위의 실수가 됩니다. 그런데 사람의 일련 번호는 1로 시작하는 정수가 되어야 한다고 하면, 먼저 1을 더해주는 것이 필요하고 그 다음에는 실수를 정수로 변환해주는 ROUND 함수를 적용하는 방식입니다. 그러면 1번부터 7번까지 7명의 사람들 중 당첨자(?)의 번호를 뽑아내는 것이 가능합니다. 공평한 추첨을 위해서는 균일 분포 기반으로 난수를 생성해야 하겠지요. 사다리 타는 것과 유사한 느낌이라고 보면 됩니다.


그리고 참고로 정규 분포 기반의 난수 생성을 위해서는 RANDOMN이란 함수를 사용하는 것도 가능합니다. 물론 RANDOMN 함수는 RANDOMU 함수를 NORMAL 키워드와 함께 사용한 경우와 똑같습니다. RANDOMN 함수에 관한 내용은 IDL 도움말을 찾아서 보시길 권합니다.

LIST