온라인 서비스 등 제품을 개발하는 과정에서 A/B 테스트의 중요성이 점점 높아지고 있습니다. A/B 테스트는 우리가 선택한 방안으로 인해 어떤 변화가 나타났는지, 인과적인 효과를 가장 효과적으로 추정할 수 있는 방법입니다. 이번주에 마케팅을 시작했더니 저번주 대비 매출이 10% 올랐다고 해서 그걸 다 마케팅의 효과라고 볼 수는 없습니다. 매출에 영향을 주는 요인은 너무나도 많으니까요. 하지만 동일한 기간 동안 A/B 테스트를 수행한 결과 두 그룹간의 매출이 10% 차이가 났다면, 이번에는 마케팅 효과라고 봐도 무방한 수치적인 근거가 될 겁니다. 또한 실험을 반복하며 제품을 개선하면 이 효과는 복리처럼 계속 누적됩니다. 매달 5%씩 지표를 향상시킬 수 있다면 단순 계산으로 1년간 80%의 개선이 이루어지는 결과가 나옵니다. 게다가 A/B 테스트로 효과를 본 기업과 팀이 점점 많아지고 있으며, 성공적인 실험을 통해 제품을 급격히 성장시키는 것은 저같은 데이터쟁이들에게는 엄청난 로망입니다.
데이터를 다루는 사람들은 A/B 테스트의 결과를 평가하기 위해서 다양한 통계적 기법을 활용하고 있는데요. 일반적으로 A/B 테스트 결과를 평가하기 위해서는 NHST(Null Hypothesis Significance Testing) 라는 프로세스를 활용하게 됩니다. 우리말로 옮겨보면 “귀무가설을 사용하는 유의성 테스트” 정도가 되겠네요. 혹시라도 통계학 입문 정도의 수업을 들으셨거나, 따로 A/B 테스트에 대해 공부해보셨다면 “가설검정” 이라는 표현을 들어보신 적이 있으실 겁니다. p-value 라는 표현이 귀에 익숙하실 수도 있겠네요. 먼저 여기서부터 시작해볼까요? NHST가 어떻게 동작하는지 알아봅시다.
전체적인 절차를 가볍게 살펴보면 다음과 같습니다.
유의수준이 의미하는 것은 무엇일까요? A안과 B안이 실제로 차이가 없다고 가정해봅시다. 이 때 우연히 몰려든 트래픽과 여러 이유로 인해 실제와는 다른 데이터를 얻게 될 가능성이 있습니다. 이렇게 두 안 사이에 차이가 없다는 가정이 맞았는데 실험 결과는 B안이 낫다는 결과가 나오는 상황을 False Positive, 통계학에서는 1종 오류라고 합니다. 통계에서는 1종 오류를 컨트롤하는 것이 중요하다고 생각하기 때문에, 이 비율이 나올 수 있는 최대치를 실험 시작 전에 정하기로 합니다. 이 값이 바로 유의수준입니다. 유의수준을 0.05로 정했다는 것은 A안과 B안이 실제로는 차이가 없는데 차이가 있다고 잘못 판단하게 될 가능성을 5%로 제한하겠다는 의미입니다. 다시 말하면 실제로 성공적인 실험 20개가 있다면 그 중 1개 정도는 잘못된 판단을 내린 실험이 있을 지도 모른다는 겁니다. 정확한 실험을 위해서는 유의수준을 낮추면 되지만, 너무 낮추게 되면 실제로 B안이 더 나은데도 기각당하는 사례들이 점점 많아지게 됩니다.
그렇다면 p-value 는 무엇일까요? 이게 참 어렵습니다. 교과서에서 보던 구절을 읊어보자면 p-value는 “귀무가설이 맞다고 가정했을 때, 현재보다 더 극단적인 케이스의 통계랑 수치가 나올 확률”을 의미합니다. (생각해보니 학교다닐 때 교수님이 p-value 를 할머니도 이해하실 수 있게 설명해보라는 문제를 내셨는데요. 저도 제대로 이해하고 있는지 모르겠는데 이거 가능하긴 한 건가요?) A/B 테스트라는 문제만 놓고 봤을 때는 p-value를 이렇게도 설명할 수 있습니다.
동일한 샘플 크기로 A/A 테스트를 수행했을 때, 방금 본 결과와 같거나 더 극단적인 결과가 나올 확률.
이제 유의수준과 p-value 를 비교하는 의사결정 단계를 볼까요?
이 과정을 이해하시려면 “무죄 추정의 원칙”을 생각하시는 것이 좋습니다. 확실한 증거가 나오기 전까지는 기본적으로 무죄 상태인 것으로 간주합니다. 그러다가 확실한 증거가 나왔을 때 유죄 판견을 내리는 거지요. 여기서 무죄 → 유죄로 넘어가는 기준선이 바로 유의수준이 됩니다. 완전히 동일한 시안 두개를 놓고 테스트를 돌려도 가끔 유의미한 차이가 있다는 결과가 나올 수 있습니다. 이런 케이스가 100번 중에 5번은 등장할 수 있다고 우리 마음 속에 허용치를 정해둡니다. 바로 이 때, 엄청난 성과를 보이는 B안이 등장합니다. 데이터를 보니 두 안이 차이가 없다고 가정하면 이런 경우는 100번 중에 3번 정도 밖에 나올 수 없는 경우의 수입니다. 이 정도가 되면 우연히 발생할리는 없다고 판단합니다. 그리고 새로운 B안이 통계적으로 유의미한 결과가 나왔다고 말하게 되는 거죠. (조금 더 정확하게는 귀무가설을 채택하지 않습니다.)
여기까지가 보통 일반적으로 많이 사용하는 방식입니다. A/B 테스트 뿐만 아니라 논문을 작성하기 위한 실험이나 임상 실험같은 경우에도 큰 틀에서는 동일한 프로세스를 따릅니다. 검증하고자 하는 문제에 따라 실험 설계가 바뀌고 통계량을 계산하는 방법이 달라지긴 하지만, 결국 프로세스는 같습니다.
방금 앞 문단에서 제가 했던 말을 기억하시나요? 논문과 임상 실험도 동일한 프로세스를 따른다고 했습니다. 두 케이스의 공통점이 무엇일까요? 바로 잘못된 선택으로 인한 비용이 크기 때문에 보수적으로 판단해야 하는 분야라는 겁니다. 논문 내의 실험 자체가 잘못되어 문제가 발생하는 경우도 있지만, 여기서는 과학적 사실/발견으로 인정받을 수 있는 검증된 논문으로 좁혀서 설명하겠습니다. 이런 경우들은 잘못 선택했을 때 워낙 비용이 크다보니 다른 팀에서 재현이 되는지도 보고, 실험도 반복적으로 해보는 등 다양한 검증을 거친 뒤에 인정을 받게 됩니다. 어, 그러니까 NHST는 이런 환경에서 사용하기 위해 고안된 의사결정 프로세스라고 볼 수도 있겠네요.
온라인으로 제공하는 웹이나 앱 서비스를 생각해볼까요? 물론 이 경우에도 잘못된 선택을 했을 때 비용이 없지는 않습니다. 하지만 비용 자체는 훨씬 적게 들어갑니다. 문제가 발생했을 때 빠르게 롤백하거나 핫픽스를 배포할 수도 있구요. (앱은 물론 웹에 비해서 배포 과정이 복잡하다보니 더 조심스럽긴 할겁니다. 하지만 임상 실험과 비교하면 큰 부담이 아닐거에요.) 혹시 잘못된 결정을 내리더라도 실험 많이해서 고객들이 만족하는 업데이트를 여러 번 할 수 있다면 장기적으로는 큰 문제가 아닐지도 모릅니다.
환경과는 별개로 프로세스 자체에 대한 아쉬움도 있습니다. 차이가 있는지 없는지만 보고 얼마나 차이가 났는지는 의사결정에 반영되지 않는다는 부분입니다. 10% vs 11% 와 10% vs 18% 는 수치상으로 큰 차이가 있지만, NHST 프로세스 상에서는 동일하게 평가하게 됩니다. 서비스에서 변경한 내용이 모든 사람에게 동일한 효과를 주는 것이 아닐텐데, 이러한 차이를 의사결정에도 반영할 수는 없을까요?
서비스 개선을 목적으로 실험을 할 때 NHST에 가질 수 있는 불만 중 또 한 가지는 바로 p-value 그 자체입니다. 혹시 다른 팀원들이나 의사결정권자에게 p-value가 어떤 의미를 가지는 값인지 설명해본 경험이 있나요? 이게 너무 어렵다보니 p-value 라는 값이 잘못 사용되는 사례가 많아졌습니다. 실험을 해야 할 일은 많아졌는데, 개념은 너무 어렵고, 사실 정확히 몰라도 실험 한 번 수행하는데는 큰 문제도 없었으니까요. p-value를 비즈니스 상황에 맞게 해석할 수 있으면 좋을 텐데, 그것 또한 쉽지 않다는 점이 아쉽기도 했습니다.
아쉬운건 아쉬운건데요. 그래서 대안이 있을까요? 최근 재미있는 방법론을 발견해서 한 번 정리를 해봤습니다. 최근 나온 논문도 아니고, 실제 의도대로 잘 동작하는지 검증도 필요하겠지만 상당히 마음에 들었거든요. 바로 Expected Loss를 사용하는 베이지안 A/B 테스트입니다.
시작하기 전에 갑자기 뜬금없이 등장한 “베이지안”이라는 단어에 대해서만 가볍게 설명하고 지나가겠습니다. 통계학에는 Frequentist(빈도주의)와 Bayesian(베이지안) 이라는 두 가지 큰 갈래가 있습니다. 두 학파는 확률에 대한 정의부터 시작해서 문제를 정의하고 해결하는 방식이 상당히 다릅니다. 이론적으로만 놓고 보면 많은 부분에서 수렴하고, 대부분 두 가지 방식 모두로 문제를 해결할 수 있습니다. 하지만 현실 문제에 적용하려고 하면 각자의 장단점이 존재합니다.
위에서 설명했던 NHST의 경우 Frequentist 방법론에 가깝습니다. 그러면 베이지안은 어떻게 데이터를 가지고 판단하게 될까요? 베이지안은 크게 다음과 같은 순서로 의사결정 합니다.
여기서 사전 확률이라는 부분이 잘 이해가 안될 수도 있습니다. 혹시 야구 좋아하시나요? 한 시즌을 거치다보면 타자들은 보통 0.2 ~ 0.3 정도의 타율로 시즌을 마무리합니다. 0.3만 넘어도 리그의 수준급 타자가 될 거고, 0.4를 넘는 경우는 좀처럼 나오지 않습니다. 만약 이 정보를 알고 있다면, 올해의 리그 평균 타율을 얼마 정도로 예상할 수 있을까요? 야구에 대한 정보가 없을 때는 0~1 사이의 어딘가로 막연히 유추하겠지만, 야구에 대한 정보가 생기면 0.2~0.3 사이의 값으로 범위를 좁힐 수 있게 됩니다. 이러한 정보를 바탕으로 타자들의 성적을 보며 데이터를 반영해 실제 예상 타율을 구하는 거죠. 원래 알고 있던 정보에 데이터를 계속 반영하여 업데이트를 반복한다는 것이 베이지안의 핵심 로직입니다.
앞서 설명드렸던 베이지안 통계도 다양한 가설 검정 프로세스를 가지고 있습니다. 이번에는 그 중에서도 Expected Loss, 즉 기대 손실을 중심으로 하는 방법에 대해 알아보려고 합니다. 이 방식은 기대 손실을 최소화하는 것을 목표로 실험을 진행합니다.
기대 손실이란 무엇일까요? 만약 우리가 B안을 선택했는데 A안의 지표가 더 좋으면 A안의 지표 - B안의 지표
만큼 손실이 생기게 될 겁니다. 데이터가 많이 쌓여서 예상되는 평균 손실을 구할 수가 있게 되면, 그게 바로 기대 손실이라고 볼 수 있습니다. 조금 더 구체적으로 보면 다음과 같이 계산합니다.
* A, B안 존재하는 상황을 가정하여 수식을 간단히 정리했습니다. * 두 안의 클릭률을 비교하는 상황을 가정했습니다. A안 선택에 대한 기대 손실 = A안 Loss Function의 기대값 B안 선택에 대한 기대 손실 = B안 Loss Function의 기대값 LossFunction(A) = max(B안의 클릭률 - A안의 클릭률, 0) LossFunction(B) = max(A안의 클릭률 - B안의 클릭률, 0) Exammple) A안의 클릭률이 0.1, B안의 클릭률이 0.15 라고 할 때 A안을 선택할 때 손실 = max(0.15 - 1, 0) = 0.05 B안을 선택할 때 손실 = max(0.1 - 0.15, 0) = 0
각 안에 대한 기대 손실을 구할 수 있게 되면, 우리는 어느 정도의 손실을 감수할 수 있는지 에러 허용치를 정합니다. 보통은 잘못된 결정을 하더라도 크게 문제가 되지 않을 정도로 작은 수치를 선택한다고 합니다. 바로 앞의 예시를 기준으로 한다면, 클릭률 1%p 정도 차이는 크게 문제되지 않다고 보는 경우 에러 허용치를 0.01로 둘 수 있습니다.
실험 초기에는 A안과 B안 모두 에러 허용치를 넘는 기대 손실을 보이게 됩니다. 그러다가 실험을 반복하며 데이터가 쌓이게 되면, 에러 허용치보다 작은 기대 손실을 보이는 안이 등장하게 됩니다. 해당 안을 선택하면 우리가 허용할 수 있는 에러보다 평균적으로 더 작은 손실이 발생한다는 것을 의미합니다. 그러면 그 안을 선택하는 것으로 실험을 마무리합니다.
실험 과정을 다시 한 번 정리해보면 다음과 같습니다.
e
를 정한다. e
보다 작은 값이 있는지 확인한다.e
보다 작은 안을 선택한다.그러면 이제 실제 코드로 간단히 살펴볼까요?
시뮬레이션을 통해 생성한 A안과 B안의 클릭 데이터으로 모형을 학습해 의사결정 하는 코드를 작성해보았습니다. 복잡한 모형을 작성하고 데이터를 반영하여 학습하려면 베이지안 모델링 프레임워크가 필요한데요. Python에서는 PyMC3를, R에서는 Stan을 사용해 모형을 학습했습니다.
import numpy as np import pymc3 as pm ##### (1) 시뮬레이션 데이터 생성 #### data = [np.random.binomial(1, 0.4, size=10000), np.random.binomial(1, 0.5, size=10000)] TOC = 0.01 ALPHA_PRIOR = 1 BETA_PRIOR = 1 ITERATIONS = 500 ##### (2) 모형 학습 #### with pm.Model() as ab_model: # Priors mua = pm.distributions.continuous.Beta('muA', alpha=ALPHA_PRIOR, beta=BETA_PRIOR) mub = pm.distributions.continuous.Beta('muB', alpha=ALPHA_PRIOR, beta=BETA_PRIOR) # Likelihoods pm.Bernoulli('likelihoodA', mua, observed=data[0]) pm.Bernoulli('likelihoodB', mub, observed=data[1]) # Find distribution of lif (difference) pm.Deterministic('lift', mub - mua) start = pm.find_MAP() step = pm.Slice() trace = pm.sample(ITERATIONS, step=step, start=start) ##### (3) Posterior 추출 및 Expected Loss 계산 #### lift_trace = trace['lift'][500:] ela = np.mean(np.maximum(lift_trace, 0)) elb = np.mean(np.maximum(-lift_trace, 0)) ##### (4) 의사결정 #### if ela <= TOC and elb <= TOC: print('A안과 B안의 효과는 동등한 것으로 보입니다.') elif elb < TOC: print('B안이 승리!') elif ela < TOC: print('A안이 승리!') else: print('실험을 더 진행해야 합니다.') ## 최종적으로 B안이 승리한 것으로 판단한다!
// model.stan data { int<lower = 1> N_a; int<lower = 1> N_b; int<lower = 0, upper = 1> a[N_a]; int<lower = 0, upper = 1> b[N_b]; } parameters { real<lower = 0, upper = 1> mu_a; real<lower = 0, upper = 1> mu_b; } model { mu_a ~ beta(1, 1); mu_b ~ beta(1, 1); a ~ bernoulli(mu_a); b ~ bernoulli(mu_b); }
TRUE_CTR_A <- 0.4 TRUE_CTR_B <- 0.5 TOC <- 0.01 ##### (1) 시뮬레이션 데이터 생성 #### set.seed(123) simulated_data <- list( A = rbinom(10000, 1, TRUE_CTR_A), B = rbinom(10000, 1, TRUE_CTR_B) ) ##### (2) 모형 학습 #### fit1 <- rstan::stan( file = 'model.stan', data = list( a = simulated_data$A, b = simulated_data$B, N_a = length(simulated_data$A), N_b = length(simulated_data$B) ) ) ##### (3) Posterior 추출 및 Expected Loss 계산 #### posterior_01 <- rstan::extract(fit1, pars = c('mu_a', 'mu_b')) lift_01 <- posterior_01$mu_b - posterior_01$mu_a expected_loss_a <- mean(pmax(lift_01, 0)) # 0.09463013 expected_loss_b <- mean(pmax(-lift_01, 0)) # 0 ##### (4) 의사결정 #### if (expected_loss_a <= TOC & expected_loss_b <= TOC) { print('A안과 B안의 효과는 동등한 것으로 보입니다.') } else if (expected_loss_b < TOC) { print('B안 승리!') } else if (expected_loss_a < TOC) { print('A안 승리!') } else { print('실험을 더 진행해야 합니다.') } ## 최종적으로 B안이 승리한 것으로 판단한다!
먼저 작은 개선폭에도 우호적인 실험을 구성할 수 있습니다. 새로운 안으로 변경하는 위험이 적은 비즈니스 환경이라면 적극적으로 고민해 볼 수 있는 특성입니다. 최근의 비즈니스 환경에서는 중요한 지표를 개선하기 위해 다양한 실험을 반복하는 경우가 많은데요. 작은 수치라도 개선되는 방안을 빠르게 선택할 수 있다면, 결과적으로는 더 많은 실험을 수행하여 지표를 최대한 개선할 수 있을 것이라고 기대할 수 있습니다.
두 번째는 Loss Function으로 인해 중요한 부분에서 발생한 오류가 의사 결정에 더 큰 영향을 미친다는 점입니다. 더이상 모든 에러가 동일한 영향을 주는 구조가 아니기 때문에, 10% vs 11% 보다 10% vs 15% 일 때 더 큰 영향을 줍니다. 또한 Loss Function을 조절하여 의사결정에 추가적인 가중치를 부여하는 것도 가능합니다.
세 번째 장점은 베이지안 방법론을 활용하다보니 B안이 A안보다 좋을 확률을 직접 계산할 수 있다는 것입니다. p-value 와는 다르게 훨씬 직관적으로 해석할 수 있는 확률을 바로 계산할 수 있다는 것은 엄청난 장점입니다. 또한 이번 글에서 자세히 설명하지는 않았지만, 클릭률 또는 전환율에 추가로 구매 금액의 분포까지 반영하여 전체적인 수익을 고려한 A/B 테스트 실험을 설계할 수도 있습니다. B안이 더 좋을 확률이라거나, B안을 선택했을 때 예상되는 이익을 금액의 형태로 표현할 수 있는 등 비즈니스적으로 해석하기 좋은 지표를 추출할 수 있다는 것은 엄청난 장점이 될 수 있습니다.
앞에서 Expected Loss를 사용한 베이지안 A/B 테스팅의 좋은 점에 대해 가볍게 살펴보았습니다. 분명 뚜렷한 장점이 있는 방법론인데요. 사용할 때 주의해야 할 점이라거나, 고민이 생긴 부분들도 정리해보려고 합니다.
먼저 여전히 남아있는 큰 고민이 하나 있습니다. 프로덕트가 장기적으로 크게 성장하기 위해 “신중한 큰 걸음”과 “신속한 잰 걸음” 중에서 어떤 방법을 선택해야 할까요? 우선 여기서 제안하는 방식은 새로운 방안을 선택하는 비용이 생각보다 적다는 것을 전제로 하고 있습니다. 그런데 정말로 그런가요? 실제로 눈에 보이는 비용은 아니지만 테스트로 인해 UI가 자주 변경되어 고객이 피로감을 느끼는 경우도 종종 있습니다. 또한 위에서 소개한 베이지안 A/B 테스트를 사용할 경우 기존 방법론 대비 1종 오류가 더 많이 발생할 수 있다는 우려를 제기하는 분들도 있습니다. NHST의 실험은 현재 안이 더 좋은데도 불구하고 성과가 더 낮은 다른 안이 실험을 이기는 1종 오류를 유의수준(보통 0.05) 이내로 컨트롤 하는 것이 목표입니다. 하지만 베이지안에서는 1종 오류를 일정 수준 이하로 보장해주지 않거든요. 뭐 Expected Loss 뿐만 아니라 다른 보조 지표를 추가로 동원해서 최대한 잘못된 선택을 피해갈 수 있도록 하는 방법도 논의가 되고 있는 것 같습니다.
두 번째는 새로운 도구 자체의 진입장벽입니다. 먼저 사람들이 여전히 p-value 와 NHST 프로세스에 익숙하다는 것이겠네요. 이미 많은 사람들이 “p-value가 0.05 보다 작으면 새로운 안을 채택합니다.” 라는 절차에 적응한 상태입니다. 이런 상황에서 팀 내의 다른 사람들에게 새로운 방안을 제안하려면 뭔가 확실한 장점이 없다면 어려울 수도 있을 것 같습니다. 또한 코드에서 보여드렸던 PyMC3나 Stan 모두 잘 사용하기 위해서는 일정 수준 이상의 진입장벽이 있기도 하구요.
마지막은 프로덕트를 만들어 가는 과정에서 생겨난 고민입니다. MAB 알고리즘 중에서도 톰슨 샘플링의 경우 정확하게 베이지안과 동일한 방식으로 동작하는데요. 다양한 컨텐츠의 성과에 따라 트래픽을 조정하여 장기적으로 최대의 성과를 얻을 수 있도록 해줍니다. 그러면 베이지안 A/B 테스팅이 필요하다고 생각했던 영역에 그냥 MAB를 적용해보는 것은 어떨까요? MAB와 A/B 테스트는 각각 어떤 환경에서 어떤 방식으로 활용할 때 가장 효과적인 프로세스가 될까요? 우리의 업무가 하나의 큰 실험장이 되게 하려면 어떤 것들이 준비되어 있어야 할까요?
최근 들어 프로덕트를 만드는 프로세스나 그로스해킹 등 다양한 분야를 공부하고 있습니다. 책도 많이 찾아 읽고 있구요. 그 과정에서 많은 사람들이 A/B 테스트 등 실험의 중요성과 성과를 많이 언급하는 것을 보게 되었습니다. 데이터와 실험의 중요성이 강조되는 것은 데이터를 다루던 사람으로서 굉장히 환영할 만한 현상입니다. 하지만 정작 실험을 잘 구성해서 평가하려면 어떻게 해야 하는지, 구체적으로 의사결정은 어떻게 해야 하는건지는 잘 언급되지 않는 것 같았어요. 이러한 부분에 대한 논의가 업계에서도 많이 이루어지면 좋겠습니다.
저는 현재 데이터라이즈라는 스타트업에서 현재 Product Owner 역할을 맡고 있습니다. 데이터 분석가 커리어를 따라가다가 갑자기 포지션을 옮기게 되어 처음에는 걱정도 많았지만, 지금은 오히려 더 데이터에 가까운 삶을 살고 있다는 생각이 드네요. 데이터라이즈에서는 이런 공부, 이런 고민들 함께 하실 분들을 계속 모시고 있습니다. 관심있는 분들은 채용 페이지에서 JD를 확인해주세요.