빈도론을 다루거나 베이지안을 다루거나 말이죠 뭐니 뭐니 해도 제일 많이 다루게 되는 응용문제는 확률적으로 차이가 나는가? 에 대한 문제이고, 이 확률적인 차이가 나는가를 다루는 상업적인 Application은 A/B테스트에 가장 많이 활용됩니다.
빈도론에 근거한 A/B테스트는 "그 유명한 A/B 테스트 결과를 신뢰구간을 이용해서 분석해 보는 이야기" 편에서 이미 살펴보았으니까, 이번에는 베이지안 관점의 A/B테스트를 해 보는 것이 당연한 수순이라고 생각합니다. 베이지안적인 A/B 테스트를 하기 전에 간단하게 신뢰구간등 몇 가지를 한번 들여다 보도 가려고 합니다.
다음과 같은 앱설치에 관련한 데이터가 있다고 한다면 말이죠.
일단 베이지안이라는 건 Prior와 Likelihood를 정의해야 Posterior를 만들어 낼 수 있잖습니꽈? 이런 경우에는 Likelihood가 이항분포가 되면 좋겠군요. Likelihood가 이항분포가 되면? 곧바로 타라락 Beta 분포를 이용하면 Conjugate관계를 이용할 수 있겠습니다아아. 흐뭇.
Prior를 무정보분포 즉, Unifrom(Beta(1,1))로 두고, 앱설치를 Trial, 재방문을 성공, 나머지를 재방문 실패라고 치고요, 암산으로 한번 분포를 암산해 보시죠.
이거는 Beta(1+56, 1+612-56) = Beta(57,557) 이 되겠습니다. 그쵸?
이런 식의 Posterior가 됩니다. Conjugate관계를 이용해서 손쉽게 하긴 했는데요, 항상 Conjugate 관계가 될 순 없잖아요? 그래서 시뮬레이션을 통해서 이걸 일반화된 정공법으로 한번 구해 보도록 해 보겠습니다.
➊ Prior와 Likelihood로 직접 Posterior 샘플을 만들어 보자구요.
어떤 식으로 할 거냐 하면, (MCMC방법론도 있긴 하지만) 일단 Prior를 정하고, 그 Prior는 모수에 관한 함수이니까 모든 prior값에 대하여 Likelihood를 계산한 후에 그 값이 성공 값과 같은 경우를 뽑아내서 Posterior의 분포를 확인해 보도록 하시죠.
코드는 말 그대로 간단합니다.
import numpy as np
n_draws = 100000 # ① Prior의 대이터 개수
prior = np.random.uniform(0, 1, n_draws) # ② Uniform으로 prior를 만들어내고,
def bayesian_model(parameters): # parameter : θ
result = np.random.binomial(612, parameters, 1) # ④ 전체 612회 시도에 대하여 성공확률 parameter 확률로 확률변수 채취
return result
simdata = np.empty(n_draws)
for i in range(n_draws): # ③ 모든 prior의 값에 대해서
simdata[i] = bayesian_model(prior[i]) # ⑤ prior에 대한 model의 결과값을 넣어둡니다.
posterior = prior[sim_data == 56] # ⑥ 결과값이 성공 회수인 56인 경우의 parameter만 추려냄
다음과 같은 느낌으로 histogram을 그려보면 말이죠
plt.hist(prior, bins=30, range=(0, 1))
plt.hist(posterior, bins=30, range=(0, 0.2)
이런 식으로 그 결과를 볼 수 있습니다. 머 딱 똑같진 않지만, 암산으로 구한 Posterior와 비~슷하죠?
➋ 그렇다면 이번엔 Posterior 결과에 대한 신뢰구간도 구해보면 좋겠군요. - 신뢰구간이라고 표현했지만 이해하기 좋은 수준에서 차용한 것이고 베이지안에서는 엄밀하게 이야기 하면 신용구간이라고 합니다.
잠시만요, 잠깐 예전 이야기를 떠올려보면, BootStrap 했을 때 기억할는지 모르겠는데, 신뢰구간을 샘플을 가지고 직접 세어서 구했었거든요? 그것과 똑같은 방법으로 신용구간을 따질 수 있습니다. - 조금 더 이야기 한다면 신뢰구간은 어떤 모수가 포함될 가능성을 이야기 하는 것이고, 신용구간은 모수가 어떤 값일 가능성을 이야기합니다. 조금 더 직관적이죠. 용어는 직관적이지 않은 것 같지만 말이죠. -
np.percentile(posterior, [2.5, 97.5]) # 양쪽 2.5%씩 빼서 95% 신용구간
>
array([0.06992351, 0.11948172])
이런 식으로 95%의 샘플이 있는 구간을 세어볼 수 있는데 결국 θ가 0.069~0.119 사이에 95%의 확률로 있다는 의미이고, 이것은 612명 중 56명이 재방문(성공)일 때, θ인 재방문율을 95% 신용구간으로 따진다면 [6.9%, 11.9%]으로 추정할 수 있다고 주장할 수 있습니다. 이때 평균 재방문율도 메디안으로 주장할 수 있겠는데,
np.median(posterior)
>
0.0929984274207789
즉, 9.2%의 평균 재방문율이라고 주장할 수 있다는 의미입니다. 방금 해 본 것은 Beta(1,1)의 무정보 Uniform을 Prior로 했는데,
prior = np.random.uniform(0, 1, n_draws) # ② Uniform으로 prior를 만들어내고,
Prior를 사전정보가 포함된 Beta로 설정해서 볼 수도 있겠습니다. 이런 경우의 예를 든다면, 기존의 통계가 22명 중 2명이 재방문하고, 20명이 재방문을 안 하더라..라는 경험적 통계가 있다고 하고 Prior를 설정해 보면,
prior = np.random.beta(2, 20, n_draws)
이런 식으로 설정할 수도 있겠네요. 참고로 이 결과를 보면
이런 식으로 Posterior결과를 볼 수도 있겠습니다. 후후. 그러니까 사전에 Parameter에 대한 정보가 있다면 이런 식으로도 시뮬레이션 가능합니다.
➌ 그러면, 일반적으로 알려져 있는 상식적 통계와 비교해 보는 것도 가능하겠습니다.
보통 업계에서 Retention에 대한 통계는 8% 정도라고 합디다. 그렇다면 지금 들여다보고 있는 데이터는 그것보다 결과가 좋을까요?라고 질문한다면, 이것은 다음과 같은 방법으로 따져볼 수 있겠습니다.
(posterior > 0.08).sum()/(len(posterior))
>
0.8277777777777777
오, 업계의 일반적인 Retention보다 좋을 확률이 82.7% 정도 되는군요? 야~ 이거 시뮬레이션으로 Posterior 샘플들을 구해 놓고 나니, 별의별걸 다 할 수 있군요! 편리합니다.
자, 이제는 본격 A/B테스트를 해 보시죠.
자, 이제는 여러 가지를 들여다보니 시뮬레이션에 대한 용기가 생겼을 거라고 생각합니다. 자, 다음과 같은 A/B 테스트 결과가 있다고 해 보시죠.
➍ 먼저 AB테스트를 암산으로 도전!
앱이 A, B 버전이 있다고 했을 때, A와 B를 각각 설치한 사용자수와 설치한 후에 재방문한 사용자수라고 하고, 역시나 Likelihood는 이항분포, Prior는 무정보 분포 Uniform = Beta(1,1)이라고 모형을 만들어서 문제를 풀어보시죠. 결국 그렇다면 Posterior는 각각 다음과 같겠죠. (성공은 재방문, 실패는 재방문 안 한 사람수)
• Posterior A : Beta(1+50, 1+600-50) = Beta(51, 551),
• Posterior B : Beta(1+56, 1+612-56) = Beta(57, 557)
이런 식이 되겠습니다. 이건 또 암산이 가능합니다.
이 두 개의 암산한 Posterior를 그려보면
이런 식 이거든요? 이것만 보면 두 개의 분포가 얼마나 차이가 나는지... B가 A보다 조금 나아 보이긴 합니다만, 어떤 식으로 알 수 있을까요?
$$ p_A \sim \mbox{Beta}(\alpha_A, \beta_A) \\
p_B \sim \mbox{Beta}(\alpha_B, \beta_B) $$
인 경우에 B의 확률이 A의 확률보다 클 확률은..? 아주 복잡한 과정을 거쳐 구하게 되면 다음과 같습니다.
$$ P(p_B > p_A) = \sum_{i=0}^{\alpha_B-1}\frac{B(\alpha_A+i,\beta_A+\beta_B)}{(\beta_B+i) B(1+i, \beta_B) B(\alpha_A, \beta_A) } $$
졸라 복잡하죠. 야.. 도대체 이런 걸 외우고 다니는 사람이 있느냐 하면.. 당연히 없지 않을까요? 이 방법을 위해서 계산해 볼 수는 있겠지만, 이걸 샘플을 통해서 간단하게 계산해 볼 수 있습니다. 휴. 다행. 어떤 식이냐면 Posteriror A 분포를 가진 샘플을 만들어내고, Posterior B분포를 가진 샘플을 만들어 낸 다음에 Posterior A와 Posterior B의 샘플을 비교해서 B보다 A가 클 경우의 비율을 계산해 낼 수 있습니다. 자, 볼까요?
➎ Posterior Beta 분포의 샘플을 만들어서 AB테스트의 암산결과를 대신해 보시죠.
from scipy import stats
import numpy as np
installA = 600 # A 설치
installB = 612 # B 설치
retentionA = 50 # A 재방문 (성공)
retentionB = 56 # B 재방문 (성공)
# Prior parameter
alpha = 1
beta = 1
samples = 1000
# 각 분포에 대한 샘플을 만듦
posterior_samplesA = stats.beta(alpha+retentionA,beta+installA-retentionA).rvs(samples)
posterior_samplesB = stats.beta(alpha+retentionB,beta+installB-retentionB).rvs(samples)
# 전체 샘플중 B가 A보다 큰 경우의 수 / 전체 샘플 수
(posterior_samplesA < posterior_samplesB).sum()/len(posterior_samplesA < posterior_samplesB)
>
0.686
B가 A보다 클 확률은 68.6% 정도로 볼 수 있겠습니다. 이 값은 샘플을 이용한 것이기 때문에 할 때마다 조금씩 다르긴 하니까 그 점은 참고해 주세요. 참고로 이거 잘 보니까 사실상 전체 샘플을 하나씩 서로 비교한 후에 B가 A보다 큰 경우의 값들의 합을 B가 A보다 큰 경우의 수를 나누니까 평균이라는 의미와 같군요. 그러면
print((posterior_samplesA < posterior_samplesB).mean())
>
0.686
이런 식으로 평균을 이용해서 계산할 수도 있겠습니다. 이건 팁이니까 알아두면 편리합니다. 헤헤.
➏ 마지막으로 암산없이 애초에 하고 싶었던 샘플 시뮬레이션을 통해 얻은 A와 B안의 비교를 통해서 확률적 의사결정을 해 보죠.
코드는 다음과 같습니다.
install = [600, 612] # 설치 수
retention = [50, 56] # 재방문자 수
def bayesian_model(parameters, i):
return np.random.binomial(install[i], parameters, 1)
for i in range(2) :
sim_data = np.empty(n_draws)
for j in range(n_draws):
sim_data[j] = bayesian_model(prior[j], i)
posterior.append(prior[sim_data == success[i]])
min_length = min(len(posterior[0]), len(posterior[1]))
posterior[0] = posterior[0][:min_length]
posterior[1] = posterior[1][:min_length]
이렇게 하면 posterior[0]에는 A 안이, posterior[1]에는 B 안이 담깁니다. 이걸 histogram으로 그려보면,
어때요? 암산으로 했던 것과 얼추 비슷~해 보이는군요.
이전에 했던 방법과 마찬가지로 B안이 A안보다 나을 확률을 구하는 것은
(posterior[1]>posterior[0]).mean()
>
0.708118556701031
이런 방식으로 계산할 수 있겠습니다. 이전에 계산했던 68.6%와 거의 비~슷하군요.
두서없이 좀 복잡하긴 했지만, 여러 가지 해 본 것들을 정리해 보면,
시뮬레이션을 통해서 Posterior를 만들어내는 것과 Posterior를 만들어 낸 후에 그것에 대한 신용구간도 계산해 낼 수 있었고, A, B 두 안에 대해서 Posterior 비교를 통해서 A/B 테스팅도 해 봤습니다요. 뭐 요 정도 해 보면 베이지안에 대해서 꽤나 자신감이 붙지 않았을까 생각합니다. 베이지안 A/B테스트는 이런 식으로 흘러갑니다.
베이지안의 교훈은 일반적으로 어렵게 생각될 수 있을 수도 있겠지만, 그렇게 생각만큼 딱딱하지만도 않습니다.
MAB(멀티암드밴딧)이라는 것도 있는데 말이죠, 그건 그것대로 이제는 각자 그럭저럭 이해할 수 있는 수준이라고 생각하고 은근슬쩍 넘어가려고 합니다.
댓글