몬테카를로 시뮬레이션으로 확률 분포와 랜덤 워크 추정하기
몬테카를로 시뮬레이션의 분포 샘플링, 랜덤 워크, MCMC 수렴 진단과 분산 감소 기법을 실무 관점에서 정리한다.
2026-08-14 · 최초 발행 2024-04-29
난수 표본으로 불확실성을 계산하는 방법
몬테카를로 시뮬레이션은 확률 분포에서 난수를 뽑아 관심 대상의 기대값, 발생 확률, 분포 특성을 수치적으로 근사하는 기법이다. 시뮬레이션 횟수를 N이라 할 때 표준오차는 √N에 반비례해 줄어든다. 닫힌 형태의 해를 구하기 어려운 모형에서도 계산 절차로 답을 만들 수 있다는 점이 핵심이다.
분포 샘플링은 목표 분포의 독립 표본을 만드는 과정이다. 정규분포나 베타분포처럼 직접 생성할 수 있는 경우도 있고, 역변환과 Box–Muller 같은 변환 기반 방식, 거절 샘플링, 중요도 샘플링을 사용할 수도 있다. 직접 표본화가 어려운 분포에서는 MCMC가 선택지가 된다.
랜덤 워크는 독립·동일분포 증가분을 누적해 경로를 만드는 방식이다. 격자 위에서 ±1씩 움직이는 이산 모델과 정규 증가분을 쓰는 연속 모델, 브라운 운동 근사가 여기에 속한다. 흡수·반사 경계와 장벽·포텐셜 같은 구속 조건을 어떻게 두느냐에 따라 같은 증가분이라도 결과는 달라진다.
계산 결과를 좌우하는 설계 지점
난수 생성기는 재현성과 병렬성의 출발점이다. PCG64, Philox 같은 고품질 RNG를 사용하고, 병렬 실행에서는 SeedSequence 분기나 counter-based RNG로 스트림을 분리한다. RNG의 품질은 DIEHARDER/TestU01 같은 통계 테스트로 점검할 수 있다.
목표 분포에 맞는 샘플러를 정한 뒤에는 유효 표본 크기와 편향-분산 트레이드오프를 관리한다. 꼬리가 두껍거나 차원이 높은 분포에서는 중요도 함수 설계와 MCMC 튜닝이 특히 큰 영향을 준다.
랜덤 워크 모듈은 이산 이동과 정규 증가분 모드를 구분하고, 흡수·반사·주기 경계 처리를 별도 인터페이스로 두는 편이 재사용에 유리하다. 스텝 크기와 시간 이산화에서 생기는 오차도 안정성 관점에서 제어해야 한다.
추정 결과에는 불확실성 평가가 따라야 한다. 표준오차는 표준편차/√N으로 근사할 수 있고, 95% 신뢰구간은 추정량 ± 1.96·SE 형태로 계산한다. 표본 의존성이 있으면 배치 평균이나 부트스트랩으로 보정한다. 대립표본, 층화, 제어변수는 계산량을 늘리지 않고 정확도를 높이기 위한 분산 감소 기법이다.
대규모 실행에서는 경로 생성 커널과 추정량 집계를 분리해 스케일 아웃 구조를 잡는다. 벡터화, 배치 처리, 메모리 지역성 최적화가 처리량에 영향을 주며, 운영 단계에서는 멱등성·체크포인트·로깅이 실행 안정성을 뒷받침한다.
샘플링부터 수렴 판단까지의 흐름
샘플러 선택 시 보는 특성
| 방법 | 성능(처리량) | 확장성(병렬) | 일관성/수렴 | 안정성(수치) | 운영 편의 |
|---|---|---|---|---|---|
| 직접/역변환 | 높음 | 높음 | 무편향, 빠른 수렴 | 높음 | 매우 높음 |
| 거절 샘플링 | 중간(수락률 의존) | 높음 | 무편향, 분산 가변 | 높음 | 중간(상계 설계 필요) |
| 중요도 샘플링 | 중간~높음 | 높음 | 가중치 변동성 관리 필수 | 중간 | 중간(제안 설계 필요) |
| MCMC(랜덤 워크) | 중간(상관 의존) | 중간(체인 병렬) | 점근적 정확성, 혼합 중요 | 중간 | 중간(튜닝 필요) |
직접 샘플링과 역변환은 대상 분포가 허용할 때 가장 단순하게 병렬화할 수 있다. 거절 샘플링은 수락률과 상계 함수 설계가 성능을 좌우한다. 중요도 샘플링은 가중치 변동성을 통제해야 하며, MCMC는 체인 상관과 혼합 상태를 진단해야 한다.
경로 기반 추정이 쓰이는 곳
금융 리스크와 파생상품 평가는 기하 브라운 운동 경로를 생성해 옵션 가격과 그릭스, VaR/ES를 추정하는 사례다. 제조·물류·통신 영역에서는 큐잉 네트워크의 혼잡도, 서비스 레벨을 포함한 재고 정책, 패킷 손실률을 계산하는 데 사용할 수 있다.
A/B 테스트와 베이즈 추정에서는 MCMC로 사후분포를 샘플링해 기대값, 신뢰구간, 의사결정 경계를 도출한다. 물리·엔지니어링에서는 확산·열전달·반응-확산 모형과 1/2차 통과시간, 흡수 경계에 도달할 확률을 다룬다.
표준오차는 1/√N으로 수렴한다. 대립표본·층화·제어변수를 적용하면 동일 비용 대비 분산을 3080% 줄일 수 있다. 벡터화·멀티스레딩·분산 실행은 문제 크기와 I/O 제약에 따라 처리량을 550배 높일 수 있다. 고정 씨드와 독립 스트림, 로깅과 체크포인트를 갖추면 재현 가능한 실험과 감사 추적에도 도움이 된다.
Python으로 분포 샘플링과 랜덤 워크 실행하기
전제조건: Python 3.10+, numpy >= 1.24. 외부 의존 없음. 단일 머신 벡터화 실행 가정.
# Monte Carlo: 분포 샘플링, 랜덤 워크, 간단한 MCMC
# Env: Python 3.10+, numpy 1.24+
import math
import numpy as np
# RNG 설정: 재현성과 병렬 스트림
ss = np.random.SeedSequence(2025)
rng = np.random.Generator(np.random.PCG64(ss))
# 1) 직접 샘플링 예: 원주율 추정 (단위 정사각형 내 점 샘플)
def estimate_pi(n_samples: int, batch: int = 1_000_000, rng=rng):
hits = 0
remaining = n_samples
while remaining > 0:
m = min(remaining, batch)
x = rng.random(m)
y = rng.random(m)
hits += np.count_nonzero(x*x + y*y <= 1.0)
remaining -= m
p_hat = hits / n_samples
pi_hat = 4.0 * p_hat
# 표준오차(비율의 분산 근사 사용)
se = 4.0 * math.sqrt(p_hat * (1 - p_hat) / n_samples)
return pi_hat, se
# 2) 연속 랜덤 워크(브라운 근사): 평균제곱변위(MSD) 확인
def random_walk_2d(n_steps: int, n_paths: int, dt: float = 1.0, sigma: float = 1.0, rng=rng):
# 정규 증가분
dx = rng.normal(0.0, sigma * math.sqrt(dt), size=(n_paths, n_steps))
dy = rng.normal(0.0, sigma * math.sqrt(dt), size=(n_paths, n_steps))
x = np.cumsum(dx, axis=1)
y = np.cumsum(dy, axis=1)
r2 = x**2 + y**2
msd = r2.mean(axis=0) # 이론값: 2 * sigma^2 * t
return msd
# 3) 랜덤 워크 Metropolis: 목표분포에서 샘플링 (예: 표준 정규의 절대값 이동 금지 없음)
def rw_metropolis(target_logpdf, proposal_std: float, n_samples: int, x0: float = 0.0, burn_in: int = 1000, rng=rng):
samples = np.empty(n_samples)
x = x0
logp_x = target_logpdf(x)
acc = 0
total = n_samples + burn_in
for i in range(total):
x_prop = x + rng.normal(0.0, proposal_std)
logp_prop = target_logpdf(x_prop)
if np.log(rng.random()) < (logp_prop - logp_x):
x, logp_x = x_prop, logp_x = x_prop, logp_prop
acc += (i >= burn_in)
if i >= burn_in:
samples[i - burn_in] = x
acc_rate = acc / n_samples
return samples, acc_rate
if __name__ == "__main__":
# 원주율 추정
pi_hat, se = estimate_pi(5_000_000)
print(f"pi ≈ {pi_hat:.6f} ± {1.96*se:.6f} (95% CI)")
# 2D 랜덤 워크 MSD
msd = random_walk_2d(n_steps=1000, n_paths=10000)
print(f"MSD[1000 steps] ≈ {msd[-1]:.3f} (이론: ≈ 2*sigma^2*t = 2000.0)")
# RW-Metropolis로 표준정규 샘플링
target_logpdf = lambda z: -0.5 * z * z # N(0,1)
samples, acc_rate = rw_metropolis(target_logpdf, proposal_std=1.0, n_samples=50_000)
print(f"RW-Metropolis 수용률 ≈ {acc_rate:.2f}, 샘플 평균 ≈ {samples.mean():.3f}, 분산 ≈ {samples.var():.3f}")
이 예시는 SeedSequence로 RNG 스트림을 관리하고, 원주율 추정의 표준오차와 신뢰구간을 함께 출력한다. 2차원 랜덤 워크에서는 평균제곱변위가 이론값 2·σ²·t와 맞는지 확인한다. MCMC에서는 수용률을 보면서 제안 분산을 조정하며, 약 0.2~0.5를 권장 범위로 둔다.
병렬 실행과 MCMC 튜닝에서의 균형
병렬 환경에서는 서로 다른 SeedSequence.spawn으로 RNG 스트림을 분리한다. 관리 복잡도는 커지지만 스트림 간 상관이 유입될 위험을 줄일 수 있다.
분산 감소 기법도 선택 비용이 다르다. 대립표본은 구현이 쉽고 효과가 안정적이며, 층화는 설계 비용이 든다. 제어변수는 상관이 높은 보조변수가 필요하다.
MCMC의 제안 분산이 너무 작으면 혼합이 나빠져 상관이 커지고, 너무 크면 수용률이 낮아진다. 목표 수용률은 0.2~0.4 범위에서 탐색한다. 성능 최적화는 벡터화를 먼저 적용하고, 이후 numba/JIT·멀티프로세싱·GPU를 검토한다. 이때 데이터 이동(I/O)과 메모리 사용량을 병목으로 관리해야 한다.
몬테카를로 시뮬레이션은 분포 샘플링과 랜덤 워크로 복잡한 시스템의 기대값과 리스크를 정량화한다. RNG 품질, 샘플러 선택, 수렴 진단, 분산 감소를 함께 설계해야 정확도와 비용 효율이 맞물린다.