본문으로 건너뛰기
중급약 35분

수집 데이터 품질 — 중복·누락·표본비 불일치(SRM)를 QA 가 잡아내기

태그가 발사되는 것과 수집된 데이터가 쓸 만한 것은 다르다. 중복 전송과 누락을 원인별로 나누고, DB 를 기준선으로 삼아 격차율을 계산한다. 표본비 불일치(SRM)는 카이제곱 검정을 실제 숫자로 계산해 판정하고, SRM 이 나오면 실험 결과를 왜 통째로 보류해야 하는지까지 다룬다.

  • #데이터품질
  • #SRM
  • #카이제곱
  • #중복전송
  • #AB테스트

개념

발사됐다고 쓸 만한 것은 아니다

레슨 5에서 태그가 설계대로 발사되는지 확인했다. 그런데 태그가 정상으로 발사돼도 모여 있는 데이터는 쓸 수 없는 상태 일 수 있다. 같은 구매가 두 번 집계되거나, 특정 브라우저에서만 체계적으로 빠져 있거나, A/B 테스트 배정 비율이 설계와 다르거나.

수집 데이터를 제품처럼 본다면 품질 특성도 제품처럼 나뉜다.

특성묻는 질문이 레슨에서
유일성같은 사건이 두 번 기록되지 않았는가중복
완전성일어난 사건이 빠짐없이 기록됐는가누락
정확성기록된 값이 실제 값과 같은가기준선 대조
일관성앞뒤 사건의 순서·관계가 맞는가순서 이상
대표성표본이 의도한 모집단을 대표하는가SRM

앞의 넷은 레슨 2에서 데이터베이스를 상대로 한 일과 같은 종류다. 마지막 하나가 새롭고, 실험 문화가 있는 조직에서 가장 값비싼 결함을 만든다.

중복 — 어디서 두 번이 되나

원인은 몇 가지로 정리된다.

  • 사용자 재시도 — 결제 완료 페이지에서 새로고침, 뒤로가기 후 다시 진입
  • SPA 라우팅 — 화면 전환이 페이지 로드가 아니라 상태 변경이라, 같은 컴포넌트가 다시 마운트되면서 이벤트가 재발사
  • 이중 구현 — gtag 직접 호출과 GTM 태그가 같은 이벤트를 각각 보냄. 담당자가 다르면 서로 모른다
  • 서버·클라이언트 양쪽 전송 — 측정 프로토콜(서버 전송)과 웹 태그를 같이 쓰는데 중복 제거 키가 없음
  • 재시도 로직 — 네트워크 실패 시 클라이언트가 자동 재전송

탐지는 레슨 2의 중복 패턴 그대로다. 분석 도구의 원본 데이터를 조회할 수 있다면(BigQuery 연동 등) 업무 키로 세어 본다.

-- 같은 거래가 두 번 이상 수집됐다
SELECT transaction_id, COUNT(*) AS event_count
FROM analytics_events
WHERE event_name = 'purchase'
  AND event_date BETWEEN '2026-09-01' AND '2026-09-24'
GROUP BY transaction_id
HAVING COUNT(*) >= 2
ORDER BY event_count DESC;

원본 접근이 없다면 합계 대조 로도 잡힌다. 분석 도구의 구매 건수와 DB 의 주문 건수를 같은 기간으로 비교했을 때 분석 쪽이 더 크면 중복이다.

막는 방법은 하나로 모인다. 모든 전환 이벤트에 유일한 업무 키를 실어 보내는 것. GA4 의 purchase 는 transaction_id 가 그 역할을 하고, 실제로 GA4 는 같은 transaction_id 의 중복을 걸러 준다. 그래서 transaction_id 를 매 요청마다 새로 생성하는 구현 이 특히 위험하다 — 중복 제거 장치를 스스로 무력화한 셈이 된다. 설계 리뷰에서 반드시 확인할 항목이다.

누락 — 빠진 것은 티가 안 난다

중복은 숫자가 커져서 눈에 띄지만 누락은 조용하다. 원인은 이렇다.

원인성격특징
광고·추적 차단기외부 요인막을 수 없다. 비율을 알고 있어야 한다
동의 거부(consent)정상 동작법적으로 맞는 동작이다. 결함이 아니다
페이지 이탈 전 전송 실패구현 결함클릭 직후 페이지가 넘어가면 요청이 취소된다
JS 오류로 태그 코드 미실행구현 결함콘솔에 흔적이 남는다(레슨 3)
앱 백그라운드 전환·종료플랫폼 제약모바일 앱에서 특히 잦다
느린 네트워크에서 타임아웃환경저사양·해외 사용자에게 편중된다

중요한 것은 앞의 둘과 나머지를 나누는 것 이다. 차단기와 동의 거부는 결함이 아니라 알고 있어야 하는 상수 다. 반면 이탈 전 전송 실패나 JS 오류는 고칠 수 있는 결함이고, 특정 브라우저·기기에 편중되므로 분석 결과를 왜곡한다.

누락은 기준선과 비교해야 보인다. 이 모듈의 결론 중 하나가 여기 있다 — 정본(source of truth)은 데이터베이스다. 분석 도구는 근사치이고, 둘이 다르면 DB 가 맞다.

격차율 = (DB 건수 - 분석 도구 건수) / DB 건수
 
예) 9월 1~24일 DB 주문 12,480건 / GA4 purchase 11,356건
    격차율 = (12,480 - 11,356) / 12,480 = 9.0%

이 9%가 정상인지 아닌지는 평소 값을 알아야 판단할 수 있다. 그래서 첫 작업은 기준선을 재는 것이다. 주 단위로 격차율을 기록해 두면 어느 날 15%로 튀었을 때 바로 알아챈다. 값 자체보다 변화 가 신호다.

격차율을 쪼개 보면 원인이 좁혀진다. 브라우저별·기기별·유입 경로별로 나눴을 때 한 구간만 격차가 크면 그 구간이 범인이다.

구간DBGA4격차율
Chrome 데스크톱5,2004,9405.0%
Safari iOS4,1003,36218.0%
Android Chrome3,1803,0544.0%

Safari 한 줄만 튀면 ITP·쿠키 정책 같은 플랫폼 차이일 수도, iOS 웹뷰에서 태그가 깨진 구현 결함일 수도 있다. 어느 쪽인지는 그 환경에서 레슨 5의 절차를 다시 돌려 보면 판별된다.

순서 이상

퍼널 단계는 순서가 있다. 뒤 단계가 앞 단계보다 많으면 논리적으로 불가능하다.

-- 세션별 단계 건수 — begin_checkout 없이 purchase 만 있는 세션
SELECT session_id,
       SUM(CASE WHEN event_name = 'begin_checkout' THEN 1 ELSE 0 END) AS checkout_cnt,
       SUM(CASE WHEN event_name = 'purchase'       THEN 1 ELSE 0 END) AS purchase_cnt
FROM analytics_events
WHERE event_date = '2026-09-24'
GROUP BY session_id
HAVING SUM(CASE WHEN event_name = 'purchase'       THEN 1 ELSE 0 END) >= 1
   AND SUM(CASE WHEN event_name = 'begin_checkout' THEN 1 ELSE 0 END) = 0;

이런 세션이 대량으로 나오면 앞 단계 태그가 일부 경로에서 누락된 것이다(예: 장바구니를 거치지 않는 바로구매 흐름에 begin_checkout 이 안 붙음). 퍼널 전환율이 100%를 넘는 구간 이 보인다면 같은 원인이다.

SRM — 표본비 불일치

A/B 테스트를 50:50 으로 설계했는데 실제 배정이 50:50 이 아니면 표본비 불일치(Sample Ratio Mismatch, SRM) 다. 이것이 심각한 이유는 비율 자체가 아니라, 비율이 틀어졌다는 것은 사용자가 무작위로 나뉘지 않았다는 증거 이기 때문이다. 무작위성이 깨지면 실험 결과 전체가 무효가 된다.

더 나쁜 것이 있다. 빠진 사용자는 보통 아무나가 아니다. 예를 들어 B안의 페이지가 느려서 로딩 전에 이탈한 사용자가 기록되지 않았다면, B안에서 사라진 사람들은 하필 가장 참을성이 없거나 네트워크가 느린 사용자 다. 남은 사람만 보면 B안이 더 좋아 보인다.

판정은 카이제곱 적합도 검정 으로 한다. 공식은 단순하다.

χ² = Σ (관측값 - 기대값)² / 기대값        자유도 = 그룹 수 - 1

예시 1 — 50:50 설계, 2만 명

관측: A = 10,342   B = 9,658     (합계 20,000)
기대: A = 10,000   B = 10,000
 
χ² = (10,342 - 10,000)² / 10,000 + (9,658 - 10,000)² / 10,000
   = 342² / 10,000 + 342² / 10,000
   = 11.6964 + 11.6964
   = 23.39          (자유도 1)
 
p ≈ 0.0000013

p 값이 0.0000013 이다. 무작위 배정이 정상일 때 이만큼 치우칠 확률이 100만 분의 1 정도라는 뜻이다. SRM 으로 판정한다.

예시 2 — 같은 설계, 치우침이 작을 때

관측: A = 10,050   B = 9,950
χ² = 50²/10,000 + 50²/10,000 = 0.25 + 0.25 = 0.5      p ≈ 0.48

p 가 0.48 이므로 이 정도 차이는 우연으로 충분히 설명된다. SRM 아님.

예시 3 — 90:10 설계에서는 작은 쪽이 민감하다

설계 90:10, 총 20,000명
관측: A = 17,700   B = 2,300
기대: A = 18,000   B = 2,000
 
χ² = 300²/18,000 + 300²/2,000 = 5.0 + 45.0 = 50.0     p ≈ 1.5e-12

같은 300명 차이인데 작은 쪽(기대 2,000)에서 훨씬 큰 값이 나온다. 불균등 배분 실험에서는 작은 그룹의 소수 누락도 SRM 이 된다.

판정 임계값. Microsoft 의 실험 플랫폼은 오탐을 줄이기 위해 p < 0.0005 라는 보수적인 기준을 쓴다고 공개 문서에서 밝히고 있다. 업계에서는 p < 0.01 을 쓰는 곳도 있다. 팀이 어느 기준을 쓰는지 먼저 정하고 문서에 적는 것 이 QA 가 할 일이다. 기준이 없으면 판정할 때마다 논쟁이 붙는다.

계산은 손으로 해도 되고 코드로 해도 된다.

from scipy.stats import chisquare
 
observed = [10342, 9658]
total = sum(observed)
expected = [total * 0.5, total * 0.5]   # 설계 비율을 그대로 적는다
 
stat, p = chisquare(f_obs=observed, f_exp=expected)
print(f"chi2={stat:.2f}  p={p:.8f}")

검정할 때 반드시 지킬 것.

  • 사용자 단위로 센다. 세션·페이지뷰 단위로 세면 그룹별 행동 차이 때문에 비율이 달라지는 것이 당연해져 검정이 무의미해진다
  • 설계 비율을 확인하고 넣는다. 50:50 인 줄 알았는데 램프업 중이라 90:10 이었던 경우가 흔하다
  • 세그먼트별로도 본다. 전체는 정상인데 특정 브라우저·국가·신규/재방문 구간에서만 SRM 이 나오면 원인이 거의 특정된다

SRM 의 원인 은 공개 문헌에서 네 단계로 정리돼 있다 — 배정 단계(버킷팅 오류, 잘못된 사용자 ID, 이전 실험의 잔류 효과), 실행 단계(리다이렉트, 변형별 이탈 차이), 로그 처리 단계(조인 오류), 분석 단계(편향된 세그먼트 조건). 여기에 실험자의 조작(변형별 순차 램프업)도 더해진다. 이 분류가 유용한 이유는 어느 단계를 먼저 볼지 순서를 정해 주기 때문이다.

SRM 이 나오면 할 일은 하나다. 결과 분석을 멈추는 것. 원인을 찾기 전에 "그래도 B안이 좋아 보인다"를 말하면 안 된다. 사라진 사용자가 결과를 어느 방향으로 얼마나 밀었는지 알 수 없기 때문이다. QA 가 이 말을 할 수 있는 근거가 위의 p 값이다. 숫자가 있으면 논쟁이 짧아진다.

실험 설계 전반 — 표본 크기 산정, 실험 기간, 다중 검정 문제 — 은 모듈 49의 A/B 테스트 품질 검증 레슨이 다룬다. 여기서는 수집된 데이터가 분석할 만한 상태인가 만 판정한다.

QA 의 점검 시점

시점확인
실험 시작 전배정 비율 설계값 문서화, 배정 단위(사용자/세션) 확인, 노출 이벤트 구현 확인
시작 후 첫날SRM 검정 1회. 여기서 걸리면 손실이 하루로 끝난다
실험 중 매일SRM 재검정, 전체 이벤트 수 급변 여부
분석 전SRM 최종 검정, 세그먼트별 SRM, 중복·누락 격차율

첫날 검정이 가장 값싸다. 2주짜리 실험이 끝난 뒤 SRM 을 발견하면 2주가 날아간다.

실무에서 왜 필요한가

수집 데이터의 결함은 틀린 결정을 만든다. 중복 purchase 로 전환율이 1.4배로 보이면 그 채널에 광고비가 더 들어가고, 누락으로 특정 브라우저의 전환이 낮게 잡히면 멀쩡한 기능이 "성과가 없다"며 롤백된다. 기능 결함은 사용자 한 명의 경험을 망치지만, 데이터 결함은 조직 전체의 판단을 망친다.

그리고 이 일은 QA 가 하기에 구조적으로 맞다. 데이터를 쓰는 사람(마케터·PM)은 자기 도구 안에서만 보므로 기준선과 대조할 수 없고, 구현하는 사람(개발자)은 자기 코드가 동작하는 것만 확인한다. DB 와 분석 도구를 양쪽에서 조회해 대조할 수 있는 사람이 QA 다. 이 모듈의 레슨 1·2가 여기서 쓰이는 이유다.

마지막으로, SRM 판정은 QA 가 "아니오"라고 말할 근거를 숫자로 갖는 드문 장면 이다. 결함 심각도 논쟁은 흔히 주관으로 흐르지만 p = 0.0000013 은 반박하기 어렵다. 이런 종류의 근거를 하나씩 늘려 가는 것이 QA 의 영향력이 커지는 방식이다.

실습 과제

과제 1 — 격차율 기준선 만들기 (30분)

담당 제품(또는 공개 데모 데이터)에서 최근 4주를 주 단위로 나눠 다음 표를 채운다. 분석 도구 접근이 없다면 두 개의 서로 다른 집계 원본 이면 무엇이든 된다(예: 서버 로그의 성공 응답 수와 DB 주문 수).

주차DB 건수분석 도구 건수격차격차율

그 다음 같은 기간을 브라우저·기기·유입 경로 중 하나로 쪼개 격차율을 다시 계산한다. 한 구간만 눈에 띄게 다르면 그 구간에서 레슨 5의 세 층 검증을 돌려 원인을 좁힌다. 결과를 "정상 격차율 범위는 X~Y%" 라는 한 문장으로 정리한다. 이 문장이 앞으로의 판정 기준이 된다.

과제 2 — SRM 판정 연습 (25분)

아래 네 실험에 대해 카이제곱 값과 판정을 계산한다. 손계산이든 scipy 든 상관없다. 판정 임계값은 p < 0.0005 를 쓴다.

#설계 비율관측χ²p판정
150:505,120 / 4,880
250:5050,480 / 49,520
380:207,850 / 2,150
433:33:343,400 / 3,290 / 3,310

1번과 2번을 비교하며 표본이 커질수록 같은 비율 차이가 더 쉽게 SRM 으로 판정된다 는 점을 확인한다. 4번은 자유도가 2라는 점에 주의한다. 각 행에 대해 SRM 이라면 어느 단계(배정·실행·로그 처리·분석)를 가장 먼저 의심할지 를 한 줄로 적는다.

과제 3 — 데이터 품질 점검표 (25분)

레슨 2의 정합성 점검표 형식으로, 수집 데이터용 점검표를 만든다. 최소 8개 항목을 포함한다.

  • 중복 2개 이상(거래 키 중복, 분석-DB 합계 역전)
  • 누락 2개 이상(격차율 기준 초과, 특정 세그먼트 격차 급증)
  • 순서 2개 이상(뒤 단계가 앞 단계보다 많음, 전환율 100% 초과 구간)
  • SRM 1개 이상(실행 중 실험 전부에 대한 일일 검정)
  • 설정 1개 이상(테스트 트래픽이 운영 측정 ID 로 유입되는지)

각 항목에 판정 기준(무엇이 나오면 결함인가) 과 확인 주기 를 적는다. 기준이 없는 항목은 점검표에 넣어도 아무도 판정하지 못한다.

자가 체크리스트

  • 수집 데이터의 품질 특성을 유일성·완전성·정확성·일관성·대표성으로 나눠 설명할 수 있다
  • 중복 전송의 원인 다섯 가지를 구분하고, transaction_id 가 중복 제거에 하는 역할을 안다
  • 누락 원인 중 "결함인 것"과 "알고 있어야 하는 상수"를 나눌 수 있다
  • DB 를 정본으로 두고 격차율을 계산하고, 기준선 대비 변화로 판정할 수 있다
  • 격차율을 세그먼트로 쪼개 원인 구간을 좁힐 수 있다
  • 퍼널 순서 이상(뒤 단계가 더 많음)을 조회로 찾아낼 수 있다
  • SRM 이 비율 문제가 아니라 무작위성 문제인 이유를 설명할 수 있다
  • 카이제곱 값을 직접 계산하고 자유도와 p 값으로 SRM 을 판정할 수 있다
  • SRM 검정을 사용자 단위로 해야 하는 이유를 말할 수 있다
  • SRM 이 확인되면 원인 규명 전까지 결과 분석을 보류시켜야 한다는 것을 안다

흔한 실수

  • 분석 도구 숫자를 정본으로 믿는다. 정본은 DB 다. 둘이 다르면 분석 도구를 의심한다.
  • 격차율의 기준선 없이 판정한다. 9%가 정상인지 비정상인지는 평소 값을 알아야 말할 수 있다.
  • 차단기·동의 거부로 인한 누락을 결함으로 등록한다. 이 둘은 상수다. 결함은 나머지 원인이다.
  • SRM 검정을 세션·페이지뷰 단위로 돌린다. 사용자 단위여야 한다. 아니면 검정 자체가 무의미하다.
  • 설계 비율을 확인하지 않고 50:50 으로 가정한다. 램프업 중이면 설계 비율이 다르다.
  • SRM 이 나왔는데 "그래도 결과는 이렇다"고 분석을 계속한다. 사라진 사용자가 결과를 어느 방향으로 밀었는지 알 수 없다. 멈춘다.
  • 실험이 끝난 뒤에 처음 검정한다. 첫날 돌렸으면 하루 손실로 끝났을 일이다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

DB — 데이터베이스
데이터를 넣어 두고 꺼내 쓰는 저장소. 보통 표 여러 개가 서로 연결된 형태다.
JS — 자바스크립트
웹 화면을 움직이게 만드는 프로그래밍 언어. 버튼을 눌렀을 때 일어나는 일을 적는다.
QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
ID — 식별자
무엇 하나를 다른 것과 구별하기 위해 붙인 이름이나 번호.
PM — 프로젝트 또는 제품 관리자
일정과 범위를 정하고 결정을 내리는 사람. 회사에 따라 프로젝트 관리자와 제품 관리자 둘 중 하나를 뜻한다.
ISO/IEC — 국제표준화기구·국제전기기술위원회 공동 표준
두 국제 단체가 함께 낸 표준이라는 표시. 뒤에 붙는 숫자가 문서 번호다.
HEART — 하트 지표
사용자 경험을 다섯 갈래 숫자로 재는 틀.
GSM — 목표·신호·지표
무엇을 이루려는지(목표)를 먼저 적고, 그것이 이뤄지면 어떤 흔적이 남는지(신호), 그 흔적을 무슨 숫자로 셀지(지표)를 차례로 끌어내는 방법.

용어집 전체 보기