리텐션은 왜 회사마다 다르게 나올까?

정의와 관찰 창, 코호트 절단

게시일
2026.10.29
태그
리텐션코호트지표 정의

같은 고객 1,200명의 6개월 리텐션이 정의에 따라 23.3%, 66.1%, 76.5%로 나옵니다. 세 숫자 모두 맞습니다. 다른 질문에 답했을 뿐입니다.

들어가며

마케팅 대시보드에는 D7 리텐션 35%가 떠 있고, 분석 도구에는 같은 주 같은 앱의 D7 리텐션이 18%로 나옵니다. 둘 다 같은 데이터를 읽고 있습니다.

어느 숫자가 맞을까요?

둘 다 맞습니다. 리텐션이라는 한 단어 뒤에 서로 다른 질문이 숨어 있고, 질문이 다르면 답도 다릅니다. 이번 글에서는 리텐션 정의가 갈리는 지점 세 곳을 실제 데이터로 보고, 정의서에 무엇을 적어야 비교가 가능한지 정리하겠습니다.

리텐션은 세 가지 질문입니다

리텐션은 처음 온 사람 가운데 나중에 다시 온 사람의 비율입니다. 문제는 다시 왔다를 언제로 볼 것인가입니다. 같은 데이터에 흔히 쓰는 세 가지 정의를 적용하면 전혀 다른 숫자가 나옵니다.

정의질문D7이라면어디에 맞나
달력(N일째)정확히 N일째 되는 날에 왔는가7일째 당일 활동매일 쓰는 앱. 가장 엄격하고 가장 낮게 나온다
범위(N일 안)1일째부터 N일째 사이에 한 번이라도 왔는가1~7일 중 활동주 단위로 쓰는 앱. 날짜가 어긋나도 잡힌다
롤링(N일 이후)N일째 또는 그 뒤에 한 번이라도 왔는가7일째 이후 활동아직 떠나지 않은 사람의 비율. 시간이 지나야 확정된다

그림 1. 리텐션의 세 가지 정의. 같은 N에 대해 달력 ≤ 범위, 달력 ≤ 롤링이 항상 성립합니다.

공개 데이터로 세 정의를 같은 코호트에 적용해 보겠습니다. UCI에 CC BY 4.0으로 공개된 영국 온라인 소매점의 거래 기록을 씁니다. 2010년 1월부터 3월 사이에 첫 구매를 한 고객 1,200명을 코호트로 잡고 이후 달에 구매했는지를 활동으로 봅니다. 앱의 일 단위 대신 월 단위이지만 구조는 같습니다.

import pandas as pd

d = pd.read_csv("data/uci/retail_customers.csv", parse_dates=["date"])
d["m"] = d.date.dt.year * 12 + d.date.dt.month - 1                 # 월 인덱스
first = d.groupby("Customer_ID")["m"].min()                          # 고객별 첫 구매 월
act = d.groupby(["Customer_ID", "m"]).size().reset_index()[["Customer_ID", "m"]]
act["k"] = act.m - act.Customer_ID.map(first)                        # 첫 구매 후 몇 개월째인가
cohort = first[(first >= 2010 * 12) & (first <= 2010 * 12 + 2)].index   # 2010년 1~3월 첫 구매 고객
a = act[act.Customer_ID.isin(cohort)]
for n in (1, 3, 6, 12):
    cal = a[a.k == n].Customer_ID.nunique() / len(cohort)            # 달력: n개월째 그 달에 구매
    bnd = a[(a.k >= 1) & (a.k <= n)].Customer_ID.nunique() / len(cohort)   # 범위: 1~n개월 안에 한 번이라도
    rol = a[a.k >= n].Customer_ID.nunique() / len(cohort)            # 롤링: n개월째 이후에 한 번이라도
    print(f"M{n:<2} 달력 {cal*100:5.1f}%  범위 {bnd*100:5.1f}%  롤링 {rol*100:5.1f}%")
# M1  달력  21.0%  범위  21.0%  롤링  83.8%
# M3  달력  27.8%  범위  49.8%  롤링  81.8%
# M6  달력  23.3%  범위  66.1%  롤링  76.5%
# M12 달력  19.2%  범위  80.0%  롤링  62.2%
첫 구매 후달력 (그 달에 구매)범위 (그때까지 한 번이라도)롤링 (그 이후 한 번이라도)
1개월째21.0%21.0%83.8%
3개월째27.8%49.8%81.8%
6개월째23.3%66.1%76.5%
12개월째19.2%80.0%62.2%

그림 2. 2010년 1~3월 첫 구매 고객 1,200명의 월 단위 리텐션. 출처는 UCI Online Retail II(CC BY 4.0)이고 집계는 이 글에서 직접 했습니다.

6개월째 한 줄만 봐도 23.3%, 66.1%, 76.5%입니다. 달력 정의는 6개월째 그 달에 산 사람만 세고, 범위 정의는 그 사이 언제든 한 번 산 사람을 세고, 롤링 정의는 6개월 뒤에도 여전히 사는 사람을 셉니다. 세 숫자는 서로 바꿔 쓸 수 없고, 움직이는 방향도 다릅니다. 롤링은 시간이 갈수록 내려가고 범위는 올라갑니다. 달력은 3개월째에 가장 높았다가 내려갑니다.

서두에서 예시로 든 35%와 18%는 이 차이일 가능성이 큽니다. 도구마다 기본 정의가 다르고, 화면에 그 정의가 잘 드러나지 않습니다.

리텐션 숫자 앞에는 달력인지, 범위인지, 롤링인지가 먼저 적혀 있어야 하고, 그 표시가 없는 두 숫자는 비교할 수 없습니다.

분모가 바뀌면 다른 사람을 셉니다

정의를 맞춰도 숫자가 다를 수 있습니다. 누구를 코호트에 넣는가, 즉 분모가 다르기 때문입니다. 같은 2010년 1~3월 첫 구매 고객에서 조건만 바꿔 보겠습니다.

코호트 조건분모M3 (달력)M6 (달력)
전체1,200명27.8%23.3%
첫 구매액 100 이상1,115명28.7%23.9%
첫 구매액 500 이상273명31.5%28.2%
영국 외 고객100명19.0%26.0%

그림 3. 같은 기간, 같은 정의에서 코호트 조건만 바꿨을 때. 설명을 위해 조건을 임의로 골랐습니다.

첫 구매액 500 이상으로 자르면 M6가 23.3%에서 28.2%로 오릅니다. 큰 고객이 더 오래 남는다는 사실 자체는 맞지만, 이 숫자를 전체 리텐션과 나란히 두면 리텐션이 올랐다는 착각이 생깁니다. 앱에서는 이 조건이 설치 기준인지, 첫 세션 기준인지, 튜토리얼 완료 기준인지로 나타납니다. 튜토리얼을 마친 사람만 세면 리텐션은 반드시 올라가고, 그것은 제품이 좋아진 것이 아니라 분모가 줄어든 것입니다.

리텐션의 분모는 누구를 처음 온 사람으로 치는가이고, 그 기준이 바뀌면 같은 정의에서도 숫자가 바뀝니다.

덜 찬 코호트가 평균을 끌어내립니다

세 번째 지점은 시간입니다. 6개월째 리텐션은 코호트가 생기고 6개월이 지나야 계산할 수 있습니다. 그런데 대시보드는 관찰 창의 끝, 즉 오늘까지의 데이터로 모든 코호트를 한 번에 그립니다. 최근 코호트는 아직 6개월이 안 됐으니 칸이 비어 있어야 하는데, 비어 있는 칸을 0으로 채우거나 일부만 찬 달을 완전한 달로 치는 일이 자주 생깁니다.

M1M2M3M4M5M6 2011-04 2011-05 2011-06 2011-07 2011-08 2011-09 2011-10 2011-11 ← 9일치
그림 4. 데이터가 2011년 12월 9일에 끝날 때의 코호트 격자. 검은 칸은 완전한 달이 찬 값, 빈 칸은 아직 오지 않은 달의 값입니다. 일부만 칠한 칸은 2011년 12월에 해당하는 값으로 1일부터 9일까지만 들어 있고, 2011-06 의 M6가 그중 하나입니다.

이 데이터의 마지막 달인 2011년 12월은 9일치뿐입니다. 2011년 6월 코호트의 6개월째는 바로 그 12월이라서, 그대로 계산하면 8.3%가 나옵니다. 앞 코호트들의 17%에서 26% 사이와 비교하면 절반 아래입니다. 리텐션이 무너진 것이 아니라 달이 덜 찬 것입니다.

빈 칸을 0으로 채우는 실수는 더 큽니다. 2010년 1월부터 2011년 11월까지 월별 코호트 23개의 M6 평균을 두 가지로 내 보겠습니다. 6개월이 지난 17개 코호트만으로 내면 17.2%입니다. 아직 6개월이 안 된 6개 코호트를 0으로 넣고 평균 내면 12.7%입니다. 같은 데이터에서 리텐션이 4.5%p 떨어진 것처럼 보입니다.

M6 평균을 내는 방법코호트 수M6 평균
6개월이 완전히 지난 코호트만17개 (2010-01 ~ 2011-05)17.2%
아직 안 지난 코호트를 0으로 넣고 전체23개12.7%
12월 9일치를 완전한 달로 치고 2011-06 포함18개2011-06만 8.3%로 들어감

그림 5. 미성숙 코호트를 다루는 방법에 따른 M6 평균. 출처는 UCI Online Retail II이고 집계는 이 글에서 직접 했습니다.

기준은 하나입니다. N개월째 리텐션은 코호트 시작 월에 N을 더한 달이 완전히 지나야 표시합니다. 일 단위라면 설치일에 N일을 더한 날짜가 어제 이전이어야 하고, 로그 적재가 하루 늦는 서비스라면 그저께 이전이어야 합니다. 그 전까지는 빈 칸으로 둡니다. 0도, 부분값도 아닙니다.

N일째 리텐션은 설치일에 N일을 더한 날이 지난 뒤에만 숫자이고, 그 전에는 빈 칸입니다.

정의서에 적을 것

세 지점을 정의서 한 장으로 고정하면 대시보드마다 다른 숫자가 나오는 일이 사라집니다.

항목예시정하지 않으면
활동의 정의앱 실행 (세션 시작 이벤트)로그인만 센 숫자와 실행을 센 숫자가 섞인다
코호트 기준일설치일 (첫 세션 시작일)설치 기준과 첫 구매 기준의 분모가 다르다
정의 종류달력 (N일째 당일)달력과 범위가 2~3배 차이 난다
날짜 경계UTC 자정 기준 달력일시간대가 다른 두 도구가 D1을 다르게 센다
성숙 기준설치일 + N일 ≤ 어제, 적재 지연 1일이면 그저께덜 찬 코호트가 평균을 끌어내린다
최소 코호트 크기100명 미만은 표시하지 않음작은 코호트의 변동이 추세처럼 보인다

그림 6. 리텐션 정의서의 최소 항목. 보고서의 리텐션 숫자 옆에는 이 가운데 정의 종류와 코호트 기준일이 함께 적혀 있어야 합니다.

보고서를 읽을 때도 같습니다. 리텐션 숫자 옆에 정의 종류와 코호트 기준일이 없으면, 그 숫자는 다른 보고서의 숫자와 비교하지 않습니다. 비교하려면 두 보고서의 정의서를 먼저 맞춥니다[1].

리텐션은 정의서가 같을 때만 같은 지표이고, 정의서 없이 적힌 리텐션은 비교 대상이 아닙니다.

나가며

  1. 리텐션에는 달력, 범위, 롤링 세 가지 정의가 있고 같은 코호트의 6개월째 값이 23.3%, 66.1%, 76.5%로 갈렸습니다. 정의 표시 없는 숫자는 비교하지 않습니다.
  2. 분모를 바꾸면 같은 정의에서도 숫자가 바뀝니다. 첫 구매액 500 이상으로 자르자 M6가 23.3%에서 28.2%가 됐습니다.
  3. N개월째 값은 그 달이 완전히 지난 뒤에만 표시합니다. 덜 찬 코호트를 0으로 넣으면 M6 평균이 17.2%에서 12.7%로 보였고, 9일치 달을 완전한 달로 치면 8.3%가 나왔습니다[2].

용어

  • 리텐션(retention): 처음 온 사람 가운데 정해진 시점에 다시 온 사람의 비율입니다. 다시 왔다를 언제로 보는가에 따라 달력, 범위, 롤링 세 정의로 갈립니다.
  • 코호트(cohort): 같은 기준일에 시작한 사람들의 묶음입니다. 설치일, 첫 세션일, 첫 구매일 가운데 무엇을 기준으로 삼느냐가 분모를 정합니다.
  • 관찰 창(observation window): 데이터가 있는 기간입니다. 창의 끝에 가까운 코호트는 아직 지나지 않은 날의 값이 없습니다.
  • 성숙(maturity): 코호트 기준일에 N을 더한 날이 지나 N일째 값을 계산할 수 있게 된 상태입니다. 성숙 전의 값은 빈 칸으로 둡니다.
  • 변동(fluctuation): 같은 조건에서도 표본마다 우연히 달라지는 값의 흔들림입니다. 코호트가 작을수록 큽니다.

참고

  1. Croll, A., & Yoskovitz, B. (2013). Lean Analytics: Use Data to Build a Better Startup Faster. O’Reilly Media.
  2. Kohavi, R., Tang, D., & Xu, Y. (2020). Trustworthy Online Controlled Experiments: A Practical Guide to A/B Testing. Cambridge University Press.

그림 2, 3, 5의 데이터는 Chen, D. (2012). Online Retail II [Dataset]. UCI Machine Learning Repository, https://doi.org/10.24432/C5CG6D (CC BY 4.0)이며, 고객 ID가 있고 수량과 단가가 양수인 거래 805,549건을 썼습니다. 데이터는 2009년 12월 1일부터 2011년 12월 9일까지이고, 첫 구매일은 이 기간 안의 첫 거래로 정했으므로 2009년 12월 이전부터 거래하던 고객은 첫 구매가 실제보다 늦게 잡힐 수 있습니다. 활동은 해당 월에 거래가 1건 이상 있는 것이고, 코호트는 첫 구매 월 기준입니다. 그림 5의 성숙 판정은 마지막 완전한 달인 2011년 11월을 기준으로 했습니다. 서두 예시의 35%와 18%는 설명을 위해 만든 가상 숫자입니다. 고객 단위 원본은 싣지 않았습니다. 코드 실행 환경은 Python 3.12, pandas 3.0.6입니다.