반응형
지난 몬테카를로 시뮬레이션 관련 포스트들은 모두 독립 확률 변수에 기초한 것입니다. 독립 확률 변수란 확률 변수들 사이에 상관관계가 없어 각 확률 변수를 독립적으로 만들 수 있다는 말이죠. 수식으로는 두 확률 변수 X,Y에 대해 p(X,Y)=p(X)∗p(Y)와 같이 표현할 수 있을 겁니다. 하지만 확률 변수들을 독립적이지 않을 때는 어떨까요? 다시 말해서 n개의 확률 변수 x1,...,xn에 대해서 다음 수식처럼 확률 변수를 독립적으로 분해할 수 없다는 것이죠. 이럴 때에는 메트로폴리스 (metropolis) 알고리즘을 사용할 수 있습니다.
p(x1,...,xn)!=p(x1)...p(xn)
메트로폴리스 알고리즘은 다음과 같이 동작합니다.
- 정의역에 있는 독립 난수의 집합 (x11,x12,...,x1n) 로부터 시작합니다.
- 정의역에 있는 다른 독립 난수의 집합 xi+1=(xi+11,...,xi+1n)을 만들고 이는 임의의 확률 함수 Q(xi)를 사용해서 만들 수 있습니다. 함수 Q의 유일한 조건은 현재 점 x에서 새로운 점 y로 갈 확률과 현재 점 y에서 새로운 점 x로 이동하는 확률이 같아야 한다는 것입니다. (간단하게 균등 함수로 구현할 수 있겠죠)
- 균등 난수 z를 만듭니다.
- 만일 p(xi+1)/p(xi)<z 라면, xi+1=xi 이고 2 단계로 다시 돌아갑니다.
- 매우 큰 수 i에 대해 이 과정을 반복하면 xi의 집합은 목표로 하는 확률 질량 함수 p(x)를 가지게 됩니다.
파이썬 구현
예를 들어 확률 질량 함수가 p(x1,x2)=6(x0−x1)2이고 [0,1]에 있는 두 난수 x1,x2를 만들어내는 간단한 경우에 대해 파이썬으로 구현해보도록 하겠습니다.
import random
def metropolis(p, q, x=None):
while True:
x_old = x
x = q(x)
if x_old is None:
x_old = [0, 1]
if p(x) / p(x_old) < random.random():
x = x_old
yield x
def P(x):
return 6.*(x[0]-x[1])**2
def Q(x):
return [random.random(), random.random()]
for i, x in enumerate(metropolis(P, Q)):
print(x)
if i == 100: break
- x_old 변수는 처음에 x가 None 객체이므로 임의의 값을 지정합니다.
- Q는 정의역 [0,1]×[0,1]에서 무작위 점을 만들어내는 함수입니다. return 대신에 생성자 yield 함수를 사용하여 모든 계산을 한 번에 하지 않고 생성된 값으로 반복합니다.
실제로 이 코드를 돌려보면 반복된 값을 많이 만들어냅니다. 즉, 만들어낸 벡터가 이전의 벡터와 두터운 상관관계를 가질 수 있다는 것이죠. 이런 이유로 메트로폴리스 알고리즘에서는 일부를 건너 뛰어서 벡터들간의 상관관계를 없애야 합니다. 이전의 벡터로부터 독립적인 다음 벡터를 만들기 위해 충분히 큰 값을 갖는 decorrelation length 를 설정하고 이 길이에 다다를 때마다 벡터를 샘플링합니다.
def metropolis_decorrelate(p, q, x=None, ds=100):
k = 0
for x in metropolis(p, q, x):
k += 1
if k % ds == ds -1:
yield x
for i, x in enumerate(metropolis_decorrelate(P,Q)):
print(x)
if i == 100: break
반응형
'Theory > Algorithms' 카테고리의 다른 글
자료구조 - 리스트와 튜플 (List, Tuple) (0) | 2022.08.07 |
---|---|
방정식 해 찾기 - 고정점 반복법 (0) | 2022.04.02 |
몬테카를로 시뮬레이션 (5) - 적분 계산하기 (0) | 2022.03.20 |
몬테카를로 시뮬레이션 (4) - 범용 몬테카를로 엔진 (0) | 2022.03.09 |
몬테카를로 시뮬레이션 (3) - 부트스트랩 알고리즘 (bootstrap) (0) | 2022.03.09 |