LabHub
はじめる
배우기 러닝패스 코스

開発者の起業 — 作る前に検証する

4つの実験をルールどおりに判定する

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

SRM·z 검정·신뢰구간·표본 크기·Holm 보정을 표준 라이브러리로 계산하는 함수를 만들고, 실험 네 개의 결과를 정해진 규칙으로 판정한다.

왜 중요한가

작은 팀의 A/B 테스트는 표본이 적고, 매일 들여다보고, 결과가 없으면 쪼개 본다. 셋 다 우연을 발견으로 바꾸는 습관이다. 규칙을 먼저 정하고 그 규칙대로 계산해야 실험이 제품 결정을 지켜 준다.

재료

정의

단계

  1. /root/founder/ab/ab.pysrm(n_a, n_b){"chi2": x, "p": y} 를 만들고, /root/founder/ab/srm.json 에 exp1·exp2 각각 {"a": n, "b": n, "chi2": x, "p": y, "srm": true/false} 를 쓴다.
  2. ab.pyztest(ca, na, cb, nb){"diff", "z", "p", "ci_low", "ci_high"} 를 만든다(ca·cb 는 전환 수, na·nb 는 사용자 수).
  3. /root/founder/ab/result.json 에 exp1 의 a_users,a_conv,b_users,b_conv,diff,p,ci_low,ci_high,decision 을 쓴다.
  4. ab.pysample_size(p_base, mde) 를 만들고 /root/founder/ab/power.jsonbaseline(exp1 A 전환율, 소수 넷째 자리), mde(0.01), n_per_arm(= sample_size(baseline, 0.01)), exp1_min_arm(exp1 두 쪽 사용자 수 가운데 작은 것), powered(exp1_min_arm ≥ n_per_arm)를 쓴다.
  5. /root/founder/ab/peeking.json 에 exp3 의 daily_p(1일차부터 누적 합계로 계산한 p 21개), first_significant_day(누적 p < 0.05 인 첫 날, 없으면 null), final_p, final_decision(마지막 날 누적값으로 한 판정)을 쓴다.
  6. ab.pyholm(pvalues)(이름→p 딕셔너리 → 기각되는 이름의 정렬된 목록)를 만들고, /root/founder/ab/multi.json 에 exp4 의 p(v1~v5 각각 control 대비), naive(p < 0.05 인 이름, 정렬), holm을 쓴다.
  7. /root/founder/ab/segments.json 에 exp1 세그먼트 10개 각각의 p, naive(p < 0.05, 정렬), holm을 쓴다.
  8. /root/founder/ab/decision.jsonexp1(판정), exp2_trustworthy(SRM 이 없으면 true), exp3_decision(마지막 날 판정), exp4_ship(Holm 기각 목록), segment_claims(Holm 기각 세그먼트 목록)를 쓴다.

참고

표본 비율부터 확인한다

/root/founder/ab/ab.py 에 srm(n_a, n_b) 를 만들고 /root/founder/ab/srm.json 에 exp1·exp2 의 a·b·chi2·p·srm 을 쓴다.

기대값은 (n_a+n_b)/2 입니다. 자유도 1 의 카이제곱 꼬리 확률은 math.erfc(math.sqrt(chi2/2)) 로 구할 수 있습니다. SRM 기준은 p < 0.001.

두 비율의 z 검정과 95% 신뢰구간

ab.py 에 ztest(ca, na, cb, nb) 를 만든다. diff·z·p(양측)·ci_low·ci_high 를 소수 여섯째 자리로.

검정 통계량은 합동 비율의 표준오차, 신뢰구간은 각자 비율의 표준오차(비합동)입니다. Φ 는 statistics.NormalDist().cdf, 임계값은 inv_cdf(0.975).

exp1 을 판정한다

/root/founder/ab/result.json 에 exp1 의 a_users·a_conv·b_users·b_conv·diff·p·ci_low·ci_high·decision 을 쓴다.

판정 규칙: p < 0.05 이고 하한 > 0 이면 ship_b, p < 0.05 이고 상한 < 0 이면 keep_a, 그 밖은 inconclusive.

이 실험은 1%p 를 잡을 만큼 컸나

ab.py 에 sample_size(p_base, mde) 를 만들고 /root/founder/ab/power.json 에 baseline·mde·n_per_arm·exp1_min_arm·powered 를 쓴다.

p2 = p1 + mde, p̄ = (p1+p2)/2, z 값은 inv_cdf(0.975) 와 inv_cdf(0.8). 괄호 안 전체를 mde 로 나눠 제곱하고 올림합니다.

A/A 실험을 매일 들여다보면

/root/founder/ab/peeking.json 에 exp3 의 daily_p(누적 21개)·first_significant_day·final_p·final_decision 을 쓴다.

exp3_daily.csv 는 그날의 증분입니다. 1일차부터 더해 가며 그날까지의 누적 합으로 ztest 를 부르세요. 날짜는 1부터 셉니다.

변형 다섯 개 — Holm 보정

ab.py 에 holm(pvalues) 를 만들고 /root/founder/ab/multi.json 에 exp4 의 p(v1~v5)·naive·holm 을 쓴다.

각 변형을 control 과 ztest(control 이 a 쪽) 합니다. Holm 은 오름차순 k 번째(0부터)에 p·(m−k) ≤ 0.05 를 보고, 처음 실패하면 멈춥니다.

세그먼트 열 개로 쪼개 보면

/root/founder/ab/segments.json 에 exp1 세그먼트 10개의 p·naive·holm 을 쓴다.

세그먼트마다 A 와 B 를 따로 세어 같은 ztest 를 부르고, 10개 p 에 같은 holm 을 적용합니다.

실험마다 배포 판단

/root/founder/ab/decision.json 에 exp1·exp2_trustworthy·exp3_decision·exp4_ship·segment_claims 를 쓴다.

앞 단계 파일에서 모읍니다. SRM 이 있는 실험은 믿을 수 없는 실험입니다. 엿보기 반례의 결론은 첫 유의한 날이 아니라 마지막 날의 판정입니다.