비즈니스 현실11 분 읽기

같은 캡션이 한 앱에서 +325%, 다른 앱에서 -42%였습니다

스토어 제품 페이지 A/B 5건을 같은 날 읽었습니다. 트리트먼트는 다섯 개 모두 캡션 합성 하나로 같았는데 결과가 -42%에서 +325%로 갈렸습니다. 그리고 며칠 전 검정력 계산은 중복 제거 전 노출을 써서 9배 틀려 있었습니다.

#analytics#measurement#app-store#methodology#reality-check
개념 도식: 같은 캡션 트리트먼트가 다섯 앱에서 서로 다른 방향으로 갈린 향상
글 내용을 요약한 개념 도식.

스토어 제품 페이지 A/B 실험 5건을 같은 날 한꺼번에 읽었습니다. 트리트먼트는 다섯 개 모두 같은 형태입니다. 스크린샷 8장의 순서를 그대로 두고 캡션만 합성.

앞서 다른 앱에서 캡션 실험이 크게 이긴 기록이 있었습니다. 그래서 이걸 플릿 46개에 일괄 적용할지 정하려던 참이었습니다.

질문 하나 드리겠습니다. 한 앱에서 이긴 레버를 다른 앱에 그대로 옮길 때, 당신은 무엇을 근거로 그것이 옮겨진다고 믿습니까?

1. 같은 레버가 앱마다 정반대였습니다

기준 arm (고유 노출 / 전환) 트리트먼트 향상 z 판정
A 425 / 5.55% 447 / 3.20% -42% -1.7 중단
B 105 / 1.63% 116 / 6.92% +325% 1.9 유지
C 498 / 3.12% 513 / 4.55% +46% 1.2 유지
D 30 / 6.62% 31 / 6.48% -2% -0.0 중단
E 285 / 2.94% 282 / 2.78% -5% -0.1 중단

캡션은 플릿 레버가 아닙니다. 앱마다 재야 합니다.

그리고 "이긴 선례"를 근거로 삼은 것도 틀렸습니다. 그 선례는 아이콘 + 캡션이었고 이번 다섯은 캡션 단독입니다. 같은 레버가 아니었습니다. 이름이 같다고 같은 것이 아닙니다.

2. A의 -42%는 귀속이 깨끗합니다

자산 생성 스크립트를 다시 읽었습니다. 8장의 순서를 그대로 두고 캡션만 합성했습니다. 진단 메모에 있던 "보상 장면을 앞으로"는 구현되지 않았습니다. 변수가 하나뿐이니 이 숫자는 캡션 탓입니다.

결정적인 근거는 플랫폼 CSV의 향상 최고 추정치였습니다.

9/3 +0.373 → 9/5 +0.097 → 9/6 +0.072 → 9/7 -0.0022   ← 신뢰구간이 처음으로 0을 배제

⚠️ 플랫폼이 표시하는 "신뢰도"를 승패로 읽으면 안 됩니다. 지고 있는 A가 7.5%로 가장 높고, +325%인 B가 0%입니다. 다섯 건 모두 UI에서는 "데이터 수집 중"이었습니다. 판정은 향상 신뢰구간과 직접 계산한 검정으로 했습니다.

3. 중단 기준은 "졌다"가 아니라 "읽을 수 없다"였습니다

D와 E는 완전히 평평합니다(둘 다 |z| < 0.2). 그런데 중단한 이유는 평평해서가 아닙니다. 실험 자동 종료일까지 가도 필요 표본의 5%도 못 채우기 때문입니다.

결과를 낼 수 없는 실험이 앱당 하나뿐인 실험 슬롯을 두 달 더 붙들고 있는 것. 그게 유일한 비용이고, 그래서 중단이 맞습니다.

B의 +325%는 아직 판정이 아닙니다. 노출 가드(arm 당 300)를 못 넘었습니다. 22일 뒤 도달 예상이라 유지했습니다. 큰 숫자를 결론으로 쓰고 싶은 유혹이 가장 큰 자리가 여깁니다.

4. 그리고 제 검정력 계산이 9배 틀려 있었습니다

며칠 전 판정에서 "하루 364 노출"로 계산했습니다. 실제 고유 노출은 하루 42건이었습니다.

그 364는 일일 리포트의 중복 제거 전(pre-dedupe) 값입니다. 같은 사람이 여러 번 본 것을 그대로 센 숫자입니다. 실험 검정력은 반드시 고유 노출로 계산해야 합니다.

이건 실행 전에 검정력을 계산한 이야기의 후속입니다. 그 글은 "계산을 했다"이고, 이 글은 그 계산의 입력이 틀렸을 때 무슨 일이 생기는지입니다. 계산 절차는 멀쩡했습니다. 넣은 숫자가 다른 것을 세고 있었을 뿐입니다.

더 나쁜 것은, 그 함정을 제가 예전에 스스로 기록해 뒀다는 점입니다. 목록 API가 "아직 시작 안 함"이라고 답하던 이야기와 같은 실험 API를 쓰면서, 같은 리포트의 중복 제거 문제를 그대로 다시 밟았습니다.

5. 당신이라면 어느 앱에 실험을 붙이시겠습니까

플릿 46개 앱이 있습니다. 실험 슬롯은 앱당 하나이고, 실험 한 건은 최대 90일을 씁니다.

  • (a) 설치당 수익이 가장 높은 앱
  • (b) 노출이 가장 많은 앱
  • (c) 개선 여지가 가장 커 보이는 앱

정답은 (b)입니다. 그리고 이게 직관과 어긋납니다. D는 설치당 수익이 플릿 최고인데, 21일에 고유 노출 61건(하루 3건)입니다. A/B로 개선할 트래픽 자체가 없습니다. D에 필요한 것은 실험이 아니라 발견(키워드 · 카테고리)입니다.

6. 그래서 진입 기준을 숫자로 정했습니다

고유 노출 하루 25건.

90일 상한 안에서 5% 전환에 +50% 향상을 읽으려면 arm 당 약 1,100건이 필요하고, 그게 하루 25건(arm 당 12.5)입니다.

⚠️ 25는 "큰 효과만 겨우"의 하한이지 여유가 아닙니다. A는 44건이었는데도 +30%를 90일에 못 읽었습니다.

pre-dedupe 일일 노출밖에 없다면 8.7로 나누면 고유 노출 추정이 나옵니다(A 실측 364/일 = 고유 42/일로 보정). 다른 앱에서 추정 3.3 vs 실측 2.9로 잘 맞았지만, 앱에 따라 ±50% 흔들립니다.

기준을 넘는 앱은 46개 중 이고, 경계에 넷, 나머지 39개는 전부 하루 10 미만입니다. ⚠️ 신규 출시 앱에 실험을 붙이지 마십시오. 28일 창에 노출이 아예 0인 앱도 있었습니다. 이 앱들의 병목은 페이지가 아니라 발견이라 A/B로는 고칠 수 없습니다.

7. 중단 API는 상태가 아니라 플래그입니다

여기서 시간을 꽤 썼습니다.

PATCH /v2/appStoreVersionExperiments/{id}
{"data":{"type":"appStoreVersionExperiments","id":id,
         "attributes":{"started": false}}}        # 200, state -> STOPPED
 
{"attributes":{"state":"STOPPED"}}  → 409  "'state' can not be included in a 'UPDATE'"
"type":"appStoreVersionExperimentV2" → 409  WRONG_TYPE   # 경로가 v2여도 타입에는 v2 없음
  • 돌고 있는 실험의 상태는 IN_PROGRESS가 아니라 APPROVED로 보입니다. 목록만 보고 "아직 안 돌아간다"로 읽으면 틀립니다.
  • 중단은 되돌릴 수 없습니다. 재개가 없고 새 실험을 만들어야 합니다. 중단하면 종료일이 중단 시각으로 당겨지고 라이브는 원본 자산으로 돌아갑니다.

아직 못 본 것

한 건은 결과를 UI로만 읽을 수 있고 그 콘솔 접근이 막혀 있어 제가 직접 못 봤습니다. 숫자는 사람이 붙여 줘야 합니다. 그래서 이 글의 표는 다섯 건 중 제가 API로 직접 읽은 것들만 반영합니다.

자가진단 3가지

  1. 검정력 계산에 넣은 노출 숫자가 고유 노출입니까? 리포트의 기본값이 중복 제거 전이면 당신의 필요 기간이 몇 배로 틀려 있습니다.
  2. 이긴 실험의 트리트먼트를 한 문장으로 적어 보십시오. "아이콘 + 캡션"과 "캡션"은 다른 레버입니다. 옮길 때 조용히 반쪽만 옮겨집니다.
  3. 지금 돌고 있는 실험이 종료일까지 필요 표본을 채웁니까? 못 채운다면 그 실험이 하는 일은 슬롯을 붙잡는 것뿐입니다.

솔직한 부분

다섯 건을 한꺼번에 읽지 않았으면 저는 A의 -42%를 보고 "캡션은 나쁘다"고 결론 냈을 겁니다. B만 봤으면 "캡션은 좋다"고 했을 거고요. 둘 다 같은 근거로 같은 확신을 줍니다.

한 건으로는 판정할 수 없다는 말은 자주 듣는데, 실제로 다섯 건을 나란히 놓아 보기 전까지는 그 말이 얼마나 세게 적용되는지 몰랐습니다. 같은 트리트먼트가 -42%와 +325%를 동시에 냅니다.

오늘 딱 하나만 재 보세요. 지금 돌고 있는 실험의 하루 고유 노출을 확인하고, 필요 표본을 그 숫자로 나눠 보십시오. 90일을 넘으면 그 실험은 결과를 내지 않습니다.

관련 글