코호트 분석¶
왜 이 분석을?¶
문제: 전체 리텐션율만 보면 어떤 고객이 언제 이탈하는지 알 수 없다.
코호트 분석은 동일 시점에 유입된 고객 그룹의 행동 변화를 추적한다:
핵심: 시간에 따른 행동 변화를 보면 "언제" 문제가 생기는지 알 수 있다.
어떤 가설?¶
가설 예시¶
| 가설 | 검증 방법 | 예상 액션 |
|---|---|---|
| 첫 주에 이탈이 집중된다 | Week 0→1 리텐션 급락 확인 | 온보딩 강화, 첫 주 인센티브 |
| 프로모션 유입 고객은 리텐션이 낮다 | 프로모션 코호트 vs 일반 코호트 비교 | 프로모션 구조 변경, CAC 재계산 |
| 특정 기능 사용자는 이탈이 적다 | 기능 사용 여부로 코호트 분리 | 해당 기능 온보딩 시 노출 |
| 시즌 유입자는 시즌 종료 후 이탈 | 시즌별 코호트 추적 | 시즌 종료 전 리텐션 캠페인 |
분석 방법¶
1. 리텐션 코호트¶
import pandas as pd
import numpy as np
# 데이터: user_id, event_date
df['cohort'] = df.groupby('user_id')['event_date'].transform('min').dt.to_period('M')
df['event_month'] = df['event_date'].dt.to_period('M')
df['cohort_index'] = (df['event_month'] - df['cohort']).apply(lambda x: x.n)
# 코호트 테이블
cohort_table = df.groupby(['cohort', 'cohort_index'])['user_id'].nunique().unstack()
# 리텐션율 (%)
cohort_size = cohort_table[0]
retention = cohort_table.divide(cohort_size, axis=0) * 100
2. 코호트 히트맵¶
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
sns.heatmap(retention,
annot=True,
fmt='.1f',
cmap='YlGnBu',
vmin=0, vmax=100)
plt.title('Monthly Retention Cohort')
plt.xlabel('Months Since First Purchase')
plt.ylabel('Cohort (First Purchase Month)')
결과 예시:
M+0 M+1 M+2 M+3 M+4 M+5
2024-01 100% 45% 32% 28% 25% 23%
2024-02 100% 42% 30% 26% 24% -
2024-03 100% 48% 35% 30% - -
2024-04 100% 38% 25% - - - ← 문제
2024-05 100% 44% - - - -
3. 세그먼트별 코호트¶
# 유입 채널별 코호트
channel_cohort = df.groupby(['channel', 'cohort', 'cohort_index'])['user_id'].nunique().unstack()
# 결과 비교
organic = channel_cohort.loc['organic']
paid = channel_cohort.loc['paid']
# 차이 분석
diff = (organic / organic[0] * 100) - (paid / paid[0] * 100)
코호트 유형¶
획득 기반 코호트 (Acquisition Cohort)¶
- 가입/첫 구매 시점 기준
- 용도: 마케팅 채널 평가, 시즌 효과 분석
행동 기반 코호트 (Behavioral Cohort)¶
- 특정 행동 수행 여부 기준
- 예: "앱 설치 후 7일 내 구매한 유저" vs "구매 안 한 유저"
# 7일 내 구매 여부로 코호트 분리
first_purchase = df[df['event'] == 'purchase'].groupby('user_id')['event_date'].min()
signup_date = df[df['event'] == 'signup'].groupby('user_id')['event_date'].min()
days_to_purchase = (first_purchase - signup_date).dt.days
df['purchase_cohort'] = np.where(days_to_purchase <= 7, 'early_buyer', 'late_buyer')
가치 기반 코호트 (Value Cohort)¶
- 첫 구매 금액, LTV 예측치 기준
- 용도: 고가치 고객 조기 식별
비즈니스 액션¶
코호트 패턴별 대응¶
| 패턴 | 해석 | 액션 |
|---|---|---|
| M+1 급락 | 온보딩 실패 | 첫 주 경험 개선, 튜토리얼, 인센티브 |
| M+3~4 급락 | 습관화 실패 | 핵심 가치 재인식 캠페인, 새 기능 소개 |
| 특정 코호트만 낮음 | 해당 시점 이슈 | 그 시점 변경사항 확인 (가격, UI, 정책) |
| Paid 코호트 낮음 | 타겟팅 문제 | 광고 타겟 재설정, 메시지 변경 |
실제 적용 예시¶
문제: 전체 M+3 리텐션이 30% → 25%로 하락
코호트 분석:
M+0 M+1 M+2 M+3
2024-01 100% 45% 32% 30%
2024-02 100% 44% 31% 28%
2024-03 100% 43% 30% 25% ← 하락 시작
2024-04 100% 42% 28% 22%
가설: 3월에 무언가 바뀌었다
확인: - 3월 앱 업데이트: 메인 화면 UI 변경 - 3월 마케팅: 신규 광고 채널 추가
심층 분석:
# 신규 채널 코호트 분리
march_cohort = df[df['cohort'] == '2024-03']
new_channel = march_cohort[march_cohort['channel'] == 'new_channel']
existing_channel = march_cohort[march_cohort['channel'] != 'new_channel']
# 비교 결과
# new_channel M+3: 18%
# existing_channel M+3: 29%
발견: 신규 광고 채널 유입 고객의 리텐션이 현저히 낮음
액션: 1. 신규 채널 광고 타겟팅/메시지 검토 2. 신규 채널 유입자 전용 온보딩 실험 3. 채널별 CAC vs LTV 재계산 → ROI 음수면 채널 중단
주의사항¶
함정¶
- 코호트 크기 무시
- 1월 코호트 10,000명, 4월 코호트 500명 → 변동성 차이
-
해결: 신뢰구간 함께 표시, 작은 코호트 해석 주의
-
계절성 미반영
- 1월(신년) vs 8월(휴가철) 리텐션은 자연스럽게 다름
-
해결: 전년 동기 대비(YoY) 비교
-
단일 지표 함정
- 리텐션만 보면 매출/활동량 변화를 놓침
- 해결: 리텐션 + 구매액 + 빈도 코호트 함께 분석
보완 분석¶
| 한계 | 보완 방법 |
|---|---|
| "왜" 이탈하는지 모름 | VoC 분석, 이탈 설문 |
| 미래 예측 어려움 | LTV 예측 모델 |
| 행동 상세 파악 | 퍼널 분석, 세션 분석 |
고급: 코호트 기반 예측¶
리텐션 커브 피팅¶
from scipy.optimize import curve_fit
# 멱함수 피팅 (Power Law)
def retention_curve(t, a, b):
return a * (t + 1) ** (-b)
# 피팅
t = np.arange(len(retention_row))
popt, _ = curve_fit(retention_curve, t, retention_row.values)
# 12개월 후 예측
predicted_m12 = retention_curve(12, *popt)