본문 바로가기

통계학 기초

베이지안 기초3. 베이지안을 활용한 A/B Test 예시[Python]

반응형

 

 

 

여러분들의 광고 시청 및 클릭은 블로그 운영에 큰 힘이 됩니다!!

 

1. 베이지안 기초 개념 복습

- 베이지안 기초 함수: 𝑝(Θ|𝑋)=𝑝(𝑋|Θ)∗𝑝(Θ)𝑝(𝑋)p(Θ|X)=p(X|Θ)∗p(Θ)p(X)

- Posterior: p(Θ | X )

- Likelihood: p(X | Θ)

- Prior: p(Θ)

- Evidence: p(X)

 

이 부분에 대해서 모르시겠다면 이전 포스팅을 참조해주시기 바랍니다. 

 

  • 베이지안 확률의 기본 이론: URL 
  • 베이지안 확률의 수식적 이해: URL    

이번에 학습에 활용할 예시는 바로 일명 빠친코, Slot Machine입니다. 영어로는 bandit 예제로 유명한데요. Bayesian Machine Learning을 배우는 학생들이 필수 예시입니다. 이 예시가 가장 실용적인 이유는 바로 "베르누이 분포를 활용한, A/B Test이기 때문에 동일한 Logic을 CVR, CTR 등 실무적인 상황에 바로 적용할 수 있기 때문"입니다.

 

 

 

2. Bernoulli Likelihood & Conjugate Prior 

 

(1) Bernoulli Likelihood & Beta Distribution 

우리는 Likelihood를 구할 때 흔히 베르누이 분포 혹은 베타 분포를 이용해서 구한다고 한다. 여기서는 깊은 내용보다는 직관적인 이해만을 위해서 최대한 쉽게 설명하고자 한다. 

  • Point1. 언제 활용하는가? 
    • 결과값(종속변수) 오직 2가지 값만을 갖는 확률변수의 분포를 나타내는 것
  • Point2. 어떻게 표현하는가? 
    • 𝐵(𝛼,𝛽) - 𝛼 성공한 횟수, 𝛽 실패한 횟수
  • Point3. 확률 분포는 어떻게 생겼는가?

베타분포 - 출처: 위키백과

참고1. 이렇게 그림으로만 보면 이해하기가 힘드나, 밑의 예시를 통해 왜 저렇게 생겼는지 설명 예정이다. 

참고2. PDF는 Probability Density Function으로 확률 밀도함수를 의미한다. 

 

  • Point4. 왜 베타분포를 활용하여 Likelihood를 계산하는가? 
    • 결과값(종속변수)가 전환, 클릭, slot machine 등의 결과는 오직 0 또는 1로 표현되기 때문이다. 
    • 모든 실행이 독립적인 무작위 사건 변수로 활용되기 때문이다. (이항분포와는 다른 이유)
      • 베타 분포에서는 1회, 2회 3회 ~ n회 실행 모두 변수로 취급하여 학습을 진행하게 된다. 
      • 이항 분포는 그냥 n회 실행하다고 가정하고, 오직 총 결과값만이 변수이다. 
      • 참고: MLE를 계산하면 이항분포의 평균 및 표준 편차가 베타분포와 같다는 것을 표현할 수 있긴하다. 그러나 이 포스팅의 목적은 개념적 이해이니 해당 부분은 다루지 않겠다. 

참고 1. 기대 수익과 같이 정수로 표현되는 변수들에 대해서는 가우시안( ≒ 정규분포)를 활용하여 Machine Learning을 해야 맞는 것이고

 

 

 

  • 결론적인 수식: 베타 분포를 활용한 Berounlli Likelihood Distribution

베타 분포에 기반한 베이지안 확률

해당 수식은 그냥 이해 정도만 하고 넘어가자. 가장 쉽게 설명하면, Posterior를 구하기 위해서 모든 Likelihood를 Naive하게 곱해서 계산하는 것이다(앞의 기본적인 베이지안 부분). 이러한 변수는 베타 분포를 따르기 때문에 발생 확률을 고려해야 하기 때문에 베타 분포 값을 곱해주는 것이다. 조금 더 전문적으로 말하면, 이는 베이지안 사전 분포는 Conjugate Prior를 가정하고 있기 때문에 위와 같은 단순한 수식을 도출할 수 있는 것이다. 

 

※ 참고 사항 - Conjugate Prior (켤레 사전 분포)

 

Conjugate Prior란 Posterior 분포가 Prior과 동일한 분포를 따라간다는 가정이다. 이러한 가정이 있어야 베르누이 Likelihood를 통해 Posterior를 계산할 수 있다. 

 

더 깊은 이해를 하기 위해서는 아래의 논문을 참조하는 것을 권장한다. 

11. Parameter Estimation - URL Link

 

 

3. Thompson Sampling

Thompson Sampling의 이해

 

- Thompson Sampling이란 Posterior 정보로 얻은 것을 다음 실험에 Prior로 활용하여 학습을 재진행하는 방법을 말한다.

 

자세한 순서는 아래와 같다. 

 

1. Prior Distribution을 활용하여 Sampling을 진행
    → 옵션 A, B, C 의 확률을 이미 알고 있다는 가정

2. 주어진 Sample 중에서 가장 우수한 대안을 선택하여 학습 진행

    → A가 가장 우수하다고 판단 가정

3. A의 승리 확률을 관찰 → e.g 빠친코 우승 확률, CTR, CVR 등 (이 부분이 Likelihood를 관찰하는 부분)

4. 관측된 Reward를 기반으로 Posterior를 계산한다.

5. 계산된 Posterior를 기반으로 다음 실험의 Prior로 활용한다. 

 

 

4. Python Code 실습

 

(1) 실험을 위한 기초 세팅

 

1
2
3
4
5
6
7
8
9
10
11
from __future__ import print_function, division
from builtins import range
 
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import beta
from ipypb import ipb
 
 
num_trials = 2000 ## 2천번 실험 예정
bandit_probabilities = [0.20.50.75## 각 slot machine 별 우승확률(prior information)
cs

 

(2) Slot Machine이 돌아가는 Class 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
## 실험 사전 설정
 
num_trials = 2000
bandit_probabilities = [0.20.50.75]
 
class bandit:
    def __init__(self, p):
        self.p = p ## 우승 확률 
        self.a = 1 ## 베타 분포 중 uniform 가정
        self.b = 1 ## 베타 분포 중 uniform 가정
        self.n = 0
        
    ## 실험 진행 - 빠친코 당기는 영역
    def pull(self):
        ## np.random 숫자 중에서 무작위 숫자를 반환하는데, 이 우승 확률이 기존 알고 있던 정보보다 작으면 true, 크면 false를 반환
        return np.random.random() < self.p
    
    
    ## 베르누이 샘플링
    def sample(self):
        return np.random.beta(self.a, self.b)
    
    
    ## 학습된 결과를 업데이트
    def update(self, x):
        self.a += x ## 성공한 횟수
        self.b += 1-## 그 반대니까
        self.n += 1
    
cs

(3) 실험 결과 시각화를 위한 코드

 

1
2
3
4
5
6
7
8
def plot(bandits, trial):
    x = np.linspace(0,1,200)
    for b in bandits:
        y = beta.pdf(x, b.a, b.b)
        plt.plot(x,y, label = f"realp: {b.p:.4f}, win rate = {b.a-1}/ {b.n}")
    plt.title(f"bandit distributions after {trial} trials")
    plt.legend()
    plt.show()
cs

 

(4) 본격적인 실험 시작

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def experiment():
    
    ## 총3개의 bandit class가 들어오게 된다. 
    bandits = [ bandit(p) for p in bandit_probabilities ]
    
    sample_points = [10,20,50,100,200,500,1000,15001999]
    
    ## 초기 reward는 그냥 다 null임
    rewards = np.zeros(num_trials)
    
    for i in ipb(range(num_trials)):
    
        ## Thompson Sampling 진행
        ## 3개의 Bandit 중 샘플 3개가 나오게 되고
        ## 나온 3개의 Sample 중 가장 큰값의 Index를 반환하게 된다. 
        j = np.argmax( [b.sample() for b in bandits] )
 
 
        ## Posterior를 그려서 실험 진행 상황을 보여준다.
        if i in sample_points:
            plot(bandits, i)
 
        ## 가장 크다고 판단된 bandit의 실험 진행
        x = badnits[j].pull()
        
        ## update the results
        reward[i] = x
        
        ## 실험이 진행된 x 결과를 bandit j의 prior로 사용하기 위해 update
        bandits[j].update(x)
        
    ```python
        ## bandits[j].update(x)에서 일어나는 일 정리!
            #X는 True or False임.
            def update(self,x):
                self.a += x ## uniform distribution
                self.b += 1-## uniform distribution
                self.n +=1   
 
    ```
 
        # print total reward
        print("total reward earned:", rewards.sum())
        print("overall win rate:", rewards.sum() / NUM_TRIALS)
        print("num times selected each bandit:", [b.n for b in bandits])
        
        
        
 
    
if __name__ == "__main__":
    experiment()
cs

 

- 베타 분포는 어떻게 변화하는지 이해하기

10회 진행시 베타 분포 모습
- 아직 3개 슬롯간 큰 차이는 보이지 않음

각 Machine의 우승 확률 Likelihood
- 파란색: 100%
- 주황색: 85%
- 초록색: 50%


50회 진행시 베타 분포 모습
- 확률이 더 큰 초록색과 주황색으로 학습이 집중되는 것을 볼 수 있음.

각 Machine의 우승 확률 Likelihood
- 파란색: 28%
- 주황색: 55%
- 초록색: 57%

100회 진행 시 베타 분포 모습

- 이제 파란색은 더 이상 학습을 진행하지 않고, 두 slot에 집중되고 있음

각 Machine의 우승 확률 Likelihood
- 파란색: 33%
- 주황색: 51%
- 초록색: 67%

500회 진행 시 베타 분포 모습

각 Machine의 우승 확률 Likelihood
- 파란색: 27%
- 주황색: 54%
- 초록색: 74%

500회 진행시 베타 분포 모습

각 Machine의 우승 확률 Likelihood
- 파란색: 17%
- 주황색: 51%
- 초록색: 73.9%

2000회 진행시 베타 분포 모습

각 Machine의 우승 확률 Likelihood
- 파란색: 17%
- 주황색: 50.9%
- 초록색: 74.7%


 

학습이 진행될수록, C에게 역시나 Exploit-Exploration이 집중되는 것을 볼 수 있고, realp의 0.75에 점점 근접하여 win rate가 계산되는 것을 볼 수 있다. 

 

 

 

- A/B Test 최종 실험 결과 보고 

total reward earned: 1475.0
overall win rate: 0.7375
num times selected each bandit: [12, 53, 1935]

총 2천회의 실험 진행 결과, 이익을 얻은 실험은 1475번이고, 최종 확률은 약 73.7%로 보고 되었다. 

Slot Machine A / B / C 중 최종적으로 Winner로 선정된 것은 C로 총 1935번 학습이 진행되었다. 

 

 

반응형