Importance sampling 예제 구현

|

Importance sampling 예제

$N(0, 1)$에서 $[2, 3]$부분만 truncate한 pdf를 만들고 그것의 평균값을 simulation하고 싶다고 가정하자.

즉 구하고 싶은 것은

$N(0, 1)$의 pdf를 $\phi$로 쓴다.

naive

  • (1)$N(0, 1)$에서 무작정 draw하고
  • (2) $\frac{\sum_i x_i \cdot \mathbb{1}(x_i \in [2, 3])}{\sum_i \mathbb{1}(x_i \in [2, 3])}$ 를 구한다.

$[2, 3]$구간에서 draw될 확률이 적기 때문에, 대부분의 sample을 버려야한다. (TODO: N(0,1), 그림 넣기)

import numpy as np

num_samples = 30000
range_ = (4, 5)

samples = np.random.normal(0, 1, num_samples)

# 쓸만한 sample index를 가져오자.
idxl = samples >= range_[0]
idxr = samples <= range_[1]
idx = idxl & idxr

samples_in_range = samples[idx]
print("{}개 중 쓸 수 있는 sample 갯수: {}개".format(num_samples, len(samples_in_range)))

result = np.sum(samples_in_range)/len(samples_in_range)
print("결과 : {}".format(result))

30000개 중 쓸 수 있는 sample 갯수: 2개
결과 : 4.350475573377283

제대로 구해보기

실제 결과와 많이 다를 것 같다.. 해보자! 그렇게 많이 다르진 않구만…

from scipy.integrate import romberg


def integrand_norm(x, s):
    return np.exp(-0.5*(x/s)**2)/(np.sqrt(2*np.pi)*s)

def integrand_normx(x, s):
    return x*np.exp(-0.5*(x/s)**2)/(np.sqrt(2*np.pi)*s)

den = romberg(integrand_norm, range_[0], range_[1], args=(1.0, ))
num = romberg(integrand_normx, range_[0], range_[1], args=(1.0, ))
print(num/den)

4.2168307809

Importance sampling

이제 importance sampling으로 구해보자!

  • 식을 다음처럼 바꾼다.

    $h(t)$는 $U[2,3]$의 pdf이며, 따라서 식 (2)의 중간에 있는 분수꼴이 importance weight가 된다.

  • $U[2, 3]$에서 draw한다. importance weight는 이며, simulated mean은 이며 버려지는 sample은 하나도 없다!
samples = np.random.uniform(range_[0], range_[1], num_samples)

print("결과: {}".format(np.sum(samples*integrand_norm(samples, 1)/den)/num_samples))


결과: 4.1905484171505805