쇼핑몰을 운영하는 온라인 판매자가 있습니다. 애널리틱스를 통해 분석해보니 하루에 접속하는 사람이 평균 976명이고 표전편차는 352인 가우스 분포를 가짐을 알았습니다. 또한, 재고가 있을 때는 5% 확률로 구매하고 재고가 없을 때는 2% 확률로 구매한다는 것 또한 알았습니다. (재고가 없으면 당연히 물건을 팔 수 없겠지만 예제이니 재고가 없어도 물건을 팔 수 있다고 가정합니다.) 판매자는 개당 100달러인 물건의 재고를 $N$개를 유지하고 한 개의 재고를 유지하는데 하루에 30달러를 지불합니다. (업무 종료 시에 한 번에 지불합니다.) 그렇다면 판매자의 평균 일일 수입을 최대화하는 최적의 재고 개수 $N$값은 얼마일까요?
이러한 문제는 수식으로 만들기도 애매하지만 난수 생성을 통해 몬테카를로 시뮬레이션을 할 수 있습니다. 하루에 얻을 수 있는 기대 수익을 시뮬레이션하고 이를 기반으로 여러 일에 대해 반복적으로 시뮬레이션 하면 되겠죠. 물건의 재고가 있으면 방문자는 5% 확률로 물건을 구매하고 수입은 70달러가 될 것이고 재고가 없으면 방문자는 2% 확률로 물건을 구매하고 수입은 100달러가 될 것입니다. 먼저 하루에 얻을 수 있는 수익을 계산해 보겠습니다.
from random import gauss, random
def simulate_once(N):
profit = 0
loss = 30*N
instock = N
for i in range(int(gauss(976, 352))):
if instock > 0:
if random() < 0.05:
instock -= 1
profit += 100
else:
if random() < 0.02:
profit += 100
return profit - loss
- random.gauss 함수로 주어진 평균과 표준편차로 정의된 가우스 분포에서 값을 샘플링합니다. 즉, 표준편차가 352이고 976에 중심을 둔 가우스 분포에서 하루 방문자 수를 샘플링하는 것이죠.
- random.random 함수를 [0,1] 사이의 값을 균등하게 뽑아내는 함수입니다.
이제 위의 "simulate_once" 함수를 시뮬레이션 일수 $d$ 만큼 반복적으로 계산합니다. 밑의 코드에서는 $d=1000$ 으로 고정시키고 $N$의 값을 10만큼 증가시키면서 평균 수입을 계산합니다. 시뮬레이션 결과로 보아 최적의 재고 품건 개수를 대략 40개 정도임을 알 수 있습니다. 당연히 시뮬레이션 성능을 향상시키려면 $d$나 $N$을 늘리면 되겠죠.
def simulate_many(N, ap=1, rp=0.01, d=1000):
s = 0.
for k in range(1, d):
x = simulate_once(N)
s += x
mu = s/k
if k > 10 and mu - mu_old < max(ap, rp*mu):
return mu
else:
mu_old = mu
raise ArithmeticError('no convergence')
for N in range(0, 100, 10):
print(N, simulate_many(N))
>>>
0 2281.818181818182
10 1709.090909090909
20 2281.818181818182
30 2641.6666666666665
40 2666.6666666666665
50 2516.6666666666665
60 2115.3846153846152
70 2718.181818181818
80 1483.3333333333333
90 1572.7272727272727
- ap는 absolute precision, rp는 relative precision을 뜻합니다. 수렴의 조건을 ap와 rp로 정하고 평균과 직전 평균의 차이가 ap보다 작거나 혹은 현재 평균의 rp 보다 작다면 수렴했다고 가정해서 루프 문을 멈춥니다. 만약, ap, rp 값을 낮춘다면 시뮬레이션의 수렴 조건을 더 빡빡하게 잡는다는 것이고 이럴 경우에는 $d$값이 ap, rp에 비해 상대적으로 작다면 수렴을 안 할 수도 있습니다.
이 예제로부터 알 수 있는 몬테카를로 시뮬레이션의 기본 구성 요소는 다음과 같습니다.
- 시스템을 한 번 시뮬레이션하고 확률 변수 (예제에서는 가우스 확률 변수)를 사용하여 미지의 양 (하루 수익)을 모델링하는 함수 (simulate_once)
- 시뮬레이션을 여러 차례 반복해서 평균을 계산하는 함수 (simulate_many)
정리하면, 몬테카를로 시뮬레이션은 1) 난수 생성기, 2) 난수 생성기를 사용하여 시스템을 한 번 시뮬레이션하는 함수, 3) 앞의 시뮬레이션을 반복해서 호출하고 시뮬레이션 값의 평균이 수렴할 때까지 결과의 평균을 계산하는 함수, 4) 결과의 정확도를 추산하고 시뮬레이션 결과가 수렴하여 정지하는 때를 결정하는 함수 ($\delta\mu$가 정밀도 (ap, rp) 보다 작은지) 로 구성됩니다.
'Theory > Algorithms' 카테고리의 다른 글
몬테카를로 시뮬레이션 (4) - 범용 몬테카를로 엔진 (0) | 2022.03.09 |
---|---|
몬테카를로 시뮬레이션 (3) - 부트스트랩 알고리즘 (bootstrap) (0) | 2022.03.09 |
몬테카를로 시뮬레이션 (1) - 파이 계산하기 (0) | 2022.02.25 |
Cholesky Decomposition (촐레스키 분해) - 파이썬 구현 (0) | 2022.02.20 |
Trie (0) | 2021.07.15 |