-
역변환 방법( Inverse CDF Technique)머신러닝(MACHINE LEARNING)/통계(Statistics) 2021. 6. 8. 14:36반응형
0. 서론
- 컴퓨터를 쓰다 보면, 생각보다 난수를 일으킬 일들이 많이 있다. 이럴때, 보통 python 의 경우, random.random( ) 모듈을 사용하게 되면, 0~1 사이 분포의 난수가 일어나게 되는데, 그렇다면, 어떤 특정한 함수를 따르는 난수를 만들어 내고 싶다면, 어떻게 해야 할까? 라는 의문에서 이 역변환 방법(inverse CDF technique) 이 쓰이게 된다.
1. 기본적인 난수 생성기
- 앞서 말했듯, 가장 기본적인 난수 생성기는 균등분포(uniform dist.) 난수생성기이다. 따라서 이것만 가지고는 0~1 사이의 난수만 생성할 수 있지, 다른 특정한 PDF 를 가지는 난수를 생성하기는 힘들다. 하지만, 역변환 방법(Inverse CDF) 을 사용하게 된다면, 우리는 어떠한 분포를 따르는 난수생성기를 무조건 만들어 낼 수 있다는 것이다..
2. 균등분포
- 우리가 알고 있는 확률 분포 함수(PDF) 는 모두 적분해서 1이고, 이를 활용하여 누적분포 함수(CDF) 를 만들게 된다면, \(F_{X}(x) = P[X<=x] \) 를 만족시키는 누적분포함수를 만들 수 있다.
- 이때 우리의 누적분포 함수 CDF \(F_{X}(x) \) 은 범위가 0~1 을 만족시키고, 우리가 가지고 있는 기본 난수 생성기 또한 0~1 범위 사이의 분포에서 난수를 발생시킨다. 이 두개의 범위가 같으므로 우리는 뭔가 이를 활용하여, 특정분포를 나타내는 난수를 만들 수 도 있겠는데? 라는 생각이 들게 된다.
- 이를 보이기 위해, 먼저 우리가 특정 밀도 함수(PDF)를 따르는 확률 변수 X 에 대해, 누적확률 분포를 나타내주면 , \( F_{X}(x) \) 가 되게 된다.
- 이때, Uniform_dist. 를 따르는 U에 대해 \( U \sim UNIF(0,1) \) 의 함수로 정의 되는 \( Y = F_{X}^{-1}(U) \) 를 나타내어 줄 수 있게 된다. 좀 더 쉽게 말하면, \( F_{X}(x) \) 의 범위가 0~1 사이 이므로, 역함수를 취해주게 되면, 0~1 사이의 범위의 U값에 대해 \( Y = F_{X}^{-1}(U) \) 를 만족시키는 Y가 있을 수 있다는 것이다.
- 이때 생성된 Y 가 확률변수 X 와 동일한 분포를 따르게 되어 Y를 우리가 원하는 함수의 난수로 이용할 수 있다는 것인데, 이를 증명해보자.
\begin{align*}
F_{Y}(y) = P[Y <= y] \\
= P[F_{X}^{-1}(U) <= y] \\
= P[U <= F_{X}(y)] \\
= F_{X}(y)
\end{align*}- 다시 한번 정리하자면, CDF 는 0~1 사이의 값을 가지고 있고, 우리의 랜덤난수기는 0~1 사이의 랜덤 분포기를 생성시키므로, 우리의 목표는 이 랜덤 난수기를 가지고 특정확률 분포를 만족시키는 랜덤난수기로 가야한다는 것이다. 따라서 , \( Y = F_{X}^{-1}(U) \) 의 역함수를 가지고, 난수를 만들어주면 된다는 것이 결론이다.( Y가 X 와 동일한 분포를 가지는 것에 대해서는 위에 증명을 해놓았다.)
3. 난수 생성 해보기
- 우리가 원하는 함수가 만약 \(F(x) = \frac{e^{-x}}{(1+e^{-x})^2} \) (pdf of Logistic Func.)라고 했을 때, 이 F(x)를 만족시키는 난수를 어떻게 생각해야 할지 막막 하겠지만, 위의 Inverse CDF 를 적용시켜보자.
- 우선 누적 분포 함수는 \(F(x) = \frac{e^{x}}{1+e^{x}} \) (Logistic CDF Func.)를 만족시키게 되고, 이에 대한 역함수는, \(F^{-1}(U) = log(\frac{U}{1+U}) \) 이 되게 된다.
- 따라서 이 식을 따라 파이썬 코드를 만들어 주게 되면,
import math import random import scipy.stats import numpy as np # 로지스틱함수의 cdf 의 역함수 def inv_logistic_df(u): return math.log(u / (1 - u)) # 램덤 난수에 의한 inv_logistic_df 구해주기 random_num = [random.random() for _ in range(10000)] random_nums_from_logistic = [inv_logistic_df(ran_num) for ran_num in random_num] # 여기는 random_num을 함수로 표현해주기 위해서 정리. hist = np.histogram(random_nums_from_logistic) hist_dist = scipy.stats.rv_histogram(hist) # 본래의 함수 logistic func 을 나타내기 위한 x,y 설정 즉 , f(x) = x 여기서의 f(x) 는 pdf(x)이다. x = np.linspace(-10,10) y = np.exp(-x)/((1+np.exp(-x))**2) plt.hist(random_nums_from_logistic,density = True, bins = 50, label = "random_number") plt.plot(x,y, label = "logistic pdf") plt.legend() plt.show() # 본래의 함수 logistic func 을 나타내기 위한 x,y 설정 즉 , f(x) = x 여기서의 f(x)는 cdf(x) 이다. x = np.linspace(-10,10) y = np.exp(x)/(1+np.exp(x)) plt.plot(x,y,label = "logistic cdf") plt.plot(x,hist_dist.cdf(x),label = "random number") plt.legend() plt.show()
- 다음과 같이 거의 비슷한 형태의 그래프가 나오는 것을 확인 가능하다. 따라서 우리가 생성한 난수분포기는 Logistic 분포를 따르는 함수라 봐도 무방하겠다..
- (참고) 여기서의 logistic PDF 는 Logistic 함수를 써서 만든 것이 아닌, Random.random() 을 사용한 뒤 Inverse CDF 를 통해 만들어 낸 랜덤 분포이다.
4. 난수 생성해보기 2
- 이제 원안에 랜덤하게 점을 찍는다고 생각해보자. 그렇게 되면 우리는 \(F(d,\theta)\) 로 식을 표현할 수 가 있는데,
- 일반적으로 반지름이 1인원안에 찍는다 생각하면, \( \theta \) 만 신경써주고, d 는 그냥 난수분포기에서 나온값 사용하면, 되는거 아냐 ? 라고 했을 시 다음과 같은 오류가 발생한다.
- 다음과 같이 중앙에 점이 몰리게 되면서, 우리가 원하는 값과는 많이 멀어진 결과값을 가지게 된다.
- 따라서, 이러한 원의 CDF 를 먼저 구해주어, 그다음 Inverse cdf trans. 를 적용해주어야 본 값을 얻게 되는데, 이 함수의 cdf 를 구해주게 되면 \( F_{X}(x) = \frac{d^2}{r^2} \) 이 되고,
- 이에 역함수를 구해주게 되면, \(Y = r*(U^{0.5}) \) 가 되게 된다. 이를 구현하면 다음과 같이 정상전개가 되게 된다.
- 이를 구현한 코드는 다음과 같다.
import turtle import math import random wn = turtle.Screen() turtle.tracer(8,0) alex = turtle.Turtle() alex.hideturtle() r = 200 for i in range(5000): u = random.random() # d = r*(u) 일반적으로 생각하기에 쉬운 오류 d = r*(u**0.5) theta = random.random()*360 x = d * math.cos(math.radians(theta)) y = d * math.sin(math.radians(theta)) alex.penup() alex.setposition(x,y) alex.dot() turtle.update() wn.mainloop()
5. - 프로그래머스 인공지능 데브코스 참조.
반응형'머신러닝(MACHINE LEARNING) > 통계(Statistics)' 카테고리의 다른 글
정규 분포 (Gaussian Distribution) (0) 2021.06.08