Files
ds_new_user_analy/retention_analysis.md

556 lines
20 KiB
Markdown
Raw Permalink Normal View History

# Retention Analysis Script Documentation
## 개요
`retention_analysis.py`는 던전 스토커즈 게임의 신규 유저 리텐션 분석을 위한 고도화된 Python 분석 도구입니다. 이 스크립트는 통계적 방법론을 기반으로 신규 유저의 행동 패턴을 심층 분석하여 리텐션에 영향을 미치는 핵심 지표를 식별하고, 특히 D0(첫날) 이탈 문제에 대한 실행 가능한 인사이트를 제공합니다.
## 프로젝트 배경 및 필요성
현재 던전 스토커즈는 **D0 이탈률이 65.9%**로 매우 높아 서비스 지속성에 심각한 위협이 되고 있습니다. 모바일 게임 업계 평균 D0 이탈률이 25-35%인 점을 고려하면, 이는 즉각적인 개선이 필요한 critical 수준입니다.
이 스크립트는 데이터 기반의 과학적 접근을 통해:
- **리텐션 영향 요인 정량화**: 어떤 지표가 유저 리텐션에 긍정적/부정적 영향을 미치는지 통계적으로 검증
- **행동 패턴 차이 분석**: D0 이탈 유저와 잔존 유저의 게임 내 행동 패턴의 핵심 차이점 파악
- **개선 우선순위 제시**: 게임 디자인 개선을 위한 데이터 기반의 구체적이고 실행 가능한 인사이트 제공
- **예측 모델 구축**: 머신러닝을 활용한 이탈 위험 예측 및 조기 경보 시스템
## 설치 및 환경 설정
### 필수 패키지 설치
```bash
# 기본 데이터 분석 패키지
pip install pandas numpy scipy matplotlib seaborn
# 머신러닝 패키지
pip install scikit-learn
# 진행률 표시 및 유틸리티
pip install tqdm
# 선택적: 고급 분석을 위한 추가 패키지
pip install plotly jupyter ipywidgets # 인터랙티브 시각화
pip install statsmodels # 고급 통계 분석
```
### 프로젝트 구조
```
ds_new_user_analy/
├── retention_analysis.py # 메인 분석 스크립트 (562 lines)
├── retention_analysis_config.json # 설정 파일 (분석 파라미터 관리)
├── retention_analysis.md # 이 문서 (사용법 및 이론)
└── analysis_results/ # 분석 결과 저장 디렉토리
├── correlation_analysis_YYYYMMDD_HHMMSS.csv # 상관관계 분석 결과
├── d0_churn_analysis_YYYYMMDD_HHMMSS.csv # D0 이탈 분석 결과
├── feature_importance_YYYYMMDD_HHMMSS.csv # 특성 중요도 분석 결과
├── insights_report_YYYYMMDD_HHMMSS.html # HTML 인사이트 리포트
└── retention_analysis_YYYYMMDD_HHMMSS.log # 상세 실행 로그
```
## 사용법
### 기본 실행
```bash
# 명령행 인자로 CSV 파일 지정
python retention_analysis.py path/to/your/analysis_data.csv
# 대화형 모드 (파일 경로 입력 프롬프트)
python retention_analysis.py
```
### 실행 예시
```bash
# 절대 경로 사용 (권장)
python retention_analysis.py "E:\DS_Git\ds_new_user_analy\analysis_results\ds-new_user_analy-20250830_174158.csv"
# 상대 경로 사용
python retention_analysis.py analysis_results/ds-new_user_analy-20250830_174158.csv
```
### 입력 데이터 요구사항
스크립트가 정상 작동하기 위해 CSV 파일에 다음 컬럼들이 필수로 포함되어야 합니다:
**필수 컬럼:**
- `uid`: 사용자 고유 식별자
- `retention_status`: 리텐션 상태 (Retained_d0, Retained_d1, ..., Retained_d7+)
- `create_time`: 사용자 생성 시간 (ISO 8601 형식: `2025-08-13T20:14:43+09:00`)
**권장 컬럼 (분석 품질 향상):**
- `tutorial_complete`: 튜토리얼 완료 여부
- `level_up_count`: 레벨업 횟수
- `play_time_total`: 총 플레이 시간
- `COOP_entry_count`, `Solo_entry_count`: 게임 모드별 진입 횟수
- `death_Monster`, `death_Trap`, `death_PK`: 사망 원인별 통계
- `item_gain_Equipment`, `gold_gain_total`: 아이템/골드 획득량
**데이터 형식 표준:**
- `create_time`은 ISO 8601 표준 형식을 사용하며 빈 값이 없음을 보장
- 한국 시간대(+09:00) 정보를 포함하여 정확한 시간대 분석 지원
- 모든 날짜/시간 계산은 한국 표준시(KST) 기준으로 처리
## 스크립트 작동 원리 및 아키텍처
### 전체 워크플로우
```mermaid
flowchart TD
A[CSV 파일 로드] --> B[데이터 유효성 검사]
B --> C[분석 기간 정보 추출 ISO8601]
C --> D[기본 전처리 및 인코딩]
D --> E[상관관계 분석 Spearman]
E --> F[D0 이탈자 특성 분석 t-test]
F --> G[Feature Importance Random Forest]
G --> H[HTML 인사이트 리포트 생성]
H --> I[결과 파일 저장 CSV/HTML/LOG]
C --> J[시간대별 가입 패턴 분석]
C --> K[요일별 가입 패턴 분석]
J --> H
K --> H
```
### 핵심 클래스: RetentionAnalyzer
```python
class RetentionAnalyzer:
"""
리텐션 분석의 메인 엔진
- 통계적 방법론 적용
- 결과 저장 및 시각화
- 확장 가능한 분석 프레임워크
"
# 핵심 메서드들
def __init__(csv_path, config_path='retention_analysis_config.json') # 초기화
def validate_csv() # 입력 데이터 검증
def load_data() # 데이터 로드 및 기본 통계
def extract_analysis_period() # 분석 기간 및 가입 패턴 추출 (ISO 8601)
def analyze_correlations() # Spearman 상관관계 분석
def analyze_d0_churners() # D0 이탈자 vs 잔존자 비교 (t-test)
def feature_importance_analysis() # Random Forest 중요도 분석
def generate_insights_report() # HTML 리포트 생성 (콘솔로그 제외)
def run_full_analysis() # 전체 분석 파이프라인 실행
```
### 데이터 구조 및 전처리
**1. Retention Status 순서형 인코딩:**
```python
# 문자열 리텐션 상태를 순서형 수치로 변환
retention_groups = ['Retained_d0', 'Retained_d1', ..., 'Retained_d7+']
df['retention_encoded'] = df['retention_status'].map(
{status: i for i, status in enumerate(retention_groups)}
)
# 결과: Retained_d0=0, Retained_d1=1, ..., Retained_d7+=7
```
이 인코딩을 통해 리텐션 단계 간의 순서 관계를 보존하면서 수치 분석이 가능해집니다.
**2. 분석 기간 정보 추출 (create_time 기반):**
```python
# ISO 8601 형식 시간 데이터 처리
create_times = pd.to_datetime(df['create_time'], format='ISO8601')
# 한국 시간대 기준 분석
korea_dates = create_times.dt.tz_convert('Asia/Seoul').dt.date
korea_hours = create_times.dt.tz_convert('Asia/Seoul').dt.hour
korea_weekdays = create_times.dt.tz_convert('Asia/Seoul').dt.dayofweek
# 가입 패턴 분석
daily_signups = korea_dates.value_counts().sort_index() # 일별 가입자
hourly_signups = korea_hours.value_counts().sort_index() # 시간대별 가입자
weekday_signups = korea_weekdays.value_counts().sort_index() # 요일별 가입자
```
**3. 결측값 처리 전략:**
- **상관관계 분석**: 각 지표별로 pairwise deletion (해당 지표만 결측값 제거)
- **Feature Importance**: Zero imputation (게임 내 활동 없음으로 해석)
- **그룹 비교**: Complete case analysis (양쪽 그룹 모두 유효한 값만 사용)
- **시간 데이터**: ISO 8601 표준으로 완전한 데이터 보장
## 통계적 분석 방법론
### 1. 상관관계 분석 (Spearman Rank Correlation)
**목적**: 각 게임 내 지표와 리텐션 단계 간의 단조 관계를 정량화
**왜 Spearman을 선택했는가?**
- `retention_status`가 순서형 변수 (d0 < d1 < d2 < ... < d7+)
- 비모수적 방법으로 분포 가정이 불필요
- 이상치에 덜 민감
- 비선형 단조 관계도 감지 가능
**수학적 배경:**
Spearman 상관계수 ρ는 다음과 같이 계산됩니다:
```
ρ = 1 - (6 × Σd²) / (n × (n² - 1))
```
여기서:
- d: 각 관측값의 두 변수 순위 차이
- n: 샘플 크기
**코드 구현:**
```python
from scipy.stats import spearmanr
for col in numeric_columns:
# 결측값 제거
valid_data = df[[col, 'retention_encoded']].dropna()
# 최소 샘플 크기 확인 (기본값: 10)
if len(valid_data) >= min_sample_size:
corr, p_value = spearmanr(
valid_data[col],
valid_data['retention_encoded']
)
# 통계적 유의성 검정 (α = 0.05)
is_significant = p_value < 0.05
```
**결과 해석:**
- ρ > 0: 해당 지표 값이 높을수록 더 오래 게임 플레이 (긍정적)
- ρ < 0: 해당 지표 값이 높을수록 빨리 이탈 (부정적)
- |ρ| > 0.3: 중간 정도의 관계
- |ρ| > 0.5: 강한 관계
### 2. 그룹 비교 분석 (Welch's t-test)
**목적**: D0 이탈 그룹과 잔존 그룹 간의 평균 차이를 통계적으로 검정
**Welch's t-test를 선택한 이유:**
- 등분산성 가정이 불필요 (두 그룹의 분산이 달라도 됨)
- 샘플 크기가 달라도 안정적
- 게임 데이터에서 흔히 발생하는 이분산성 문제 해결
**통계적 가설:**
- H₀(귀무가설): μ₁ = μ₂ (두 그룹의 평균이 같다)
- H₁(대립가설): μ₁ ≠ μ₂ (두 그룹의 평균이 다르다)
**코드 구현:**
```python
from scipy import stats
# D0 이탈자와 잔존자 데이터 분리
d0_users = df[df['retention_status'] == 'Retained_d0']
retained_users = df[df['retention_status'] != 'Retained_d0']
for metric in key_metrics:
d0_data = d0_users[metric].dropna()
retained_data = retained_users[metric].dropna()
# Welch's t-test 수행
t_stat, p_value = stats.ttest_ind(
d0_data,
retained_data,
equal_var=False # 등분산 가정 안 함
)
# 실용적 차이 계산 (효과 크기)
d0_mean = d0_data.mean()
retained_mean = retained_data.mean()
diff_percentage = ((retained_mean - d0_mean) / (d0_mean + 0.0001)) * 100
```
**결과 해석:**
- p-value < 0.05: 통계적으로 유의한 차이 존재
- 차이율 100% 이상: 잔존자가 이탈자보다 2배 이상 높은 지표
- Cohen's d 효과 크기: |d| > 0.8 (큰 효과), 0.5-0.8 (중간), 0.2-0.5 (작은 효과)
### 3. 특성 중요도 분석 (Random Forest)
**목적**: 다변량 환경에서 리텐션 예측에 가장 중요한 변수들을 식별
**Random Forest의 장점:**
- **비선형 관계 포착**: 복잡한 게임 내 상호작용 모델링
- **변수 간 상호작용**: A와 B의 조합 효과 자동 탐지
- **과적합 방지**: 배깅과 랜덤 서브스페이스 기법 사용
- **안정성**: 아웃라이어에 견고함
- **해석 가능성**: 각 변수의 기여도 정량화
**중요도 계산 원리:**
각 변수의 중요도는 해당 변수가 모든 트리에서 불순도 감소에 기여한 평균값입니다:
```
Importance(v) = (1/T) × Σ[t=1 to T] Σ[s∈Splits(v,t)] p(s) × ΔI(s)
```
여기서:
- T: 트리 개수
- p(s): 분할 s에 도달하는 샘플 비율
- ΔI(s): 분할 s에서의 불순도 감소량
**코드 구현:**
```python
from sklearn.ensemble import RandomForestClassifier
# 데이터 준비
X = df[feature_columns].fillna(0) # Zero imputation
y = df['retention_encoded'] # 타겟 변수
# Random Forest 모델 설정
rf = RandomForestClassifier(
n_estimators=100, # 트리 개수 (안정성과 성능 균형)
random_state=42, # 재현 가능성
n_jobs=-1, # 병렬 처리
max_depth=None, # 트리 깊이 제한 없음 (자연스러운 중단)
min_samples_split=2, # 최소 분할 샘플 수
min_samples_leaf=1 # 최소 리프 샘플 수
)
# 모델 학습
rf.fit(X, y)
# 중요도 추출
importance_scores = rf.feature_importances_
```
**결과 해석:**
- 0.1 이상: 매우 중요한 변수 (핵심 개선 타겟)
- 0.05-0.1: 중요한 변수 (보조 개선 요소)
- 0.01-0.05: 보통 중요 (모니터링 지표)
- 0.01 미만: 낮은 중요도 (우선순위 후순위)
## 고급 분석 기법 및 확장
### 1. 통계적 검증 강화
**다중 비교 문제 해결:**
```python
from statsmodels.stats.multitest import multipletests
# Bonferroni 또는 FDR 보정 적용
p_values = [result['p_value'] for result in analysis_results]
rejected, p_corrected, _, _ = multipletests(p_values, method='fdr_bh')
```
**효과 크기 계산:**
```python
# Cohen's d 계산
def cohens_d(group1, group2):
pooled_std = np.sqrt(((len(group1) - 1) * group1.var() +
(len(group2) - 1) * group2.var()) /
(len(group1) + len(group2) - 2))
return (group1.mean() - group2.mean()) / pooled_std
```
### 2. 심층 세그멘테이션 분석
**클러스터링 기반 유저 타입 분류:**
```python
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# 특성 정규화
scaler = StandardScaler()
scaled_features = scaler.fit_transform(df[numeric_columns])
# K-means 클러스터링
kmeans = KMeans(n_clusters=5, random_state=42)
df['user_segment'] = kmeans.fit_predict(scaled_features)
# 세그먼트별 리텐션 패턴 분석
segment_retention = df.groupby(['user_segment', 'retention_status']).size()
```
### 3. 시계열 분석 및 트렌드
**일별/주별 리텐션 트렌드:**
```python
# 코호트 분석
df['signup_date'] = pd.to_datetime(df['signup_date'])
df['cohort'] = df['signup_date'].dt.to_period('W') # 주간 코호트
cohort_retention = df.groupby('cohort')['retention_encoded'].describe()
```
## 설정 파일 상세 설명
### retention_analysis_config.json
```json
{
"analysis_settings": {
"correlation_threshold": 0.05, // 통계적 유의수준 (Type I 오류율)
"top_n_features": 20, // 결과 표시할 상위 중요 변수 개수
"min_sample_size": 10, // 분석 최소 샘플 크기 (신뢰성 확보)
"effect_size_threshold": 0.1 // 실용적 유의성 최소 효과 크기
},
"retention_groups": [ // 리텐션 단계 정의 및 순서
"Retained_d0", "Retained_d1", "Retained_d2", "Retained_d3",
"Retained_d4", "Retained_d5", "Retained_d6", "Retained_d7+"
],
"exclude_columns": [ // 분석에서 제외할 메타데이터 컬럼
"uid", "retention_status", "retention_encoded",
"country", "nickname", "auth_id", "create_time"
],
"key_metrics_for_d0_analysis": [ // D0 분석 핵심 지표 (도메인 지식 기반)
"tutorial_complete", // 온보딩 완료도
"level_up_count", // 성장 경험
"play_time_total", // 참여도
"COOP_entry_count", "Solo_entry_count", // 게임 모드 선호
"death_Monster", "death_Trap", "death_PK", // 실패 경험
"item_gain_Equipment", "gold_gain_total" // 보상 경험
],
"output_settings": {
"save_csv": true, // 원시 데이터 CSV 저장
"save_html": true, // HTML 리포트 저장 (기본 출력)
"save_console_log": true, // 디버깅용 로그 저장
"timestamp_format": "%Y%m%d_%H%M%S" // 파일명 타임스탬프 형식
}
}
```
## 출력 결과 해석 가이드
### 상관관계 분석 결과
**긍정적 상관관계 (양의 값) 해석:**
```
shop_sell_count: 0.428 (p < 0.001)
```
→ 아이템 판매 활동이 활발한 유저일수록 더 오래 게임을 플레이하는 경향
**액션 아이템**: 거래 시스템 개선, 마켓플레이스 UX 향상
**부정적 상관관계 (음의 값) 해석:**
```
dungeon_first_result: -0.173 (p < 0.01)
```
→ 첫 던전에서 실패한 유저일수록 빨리 이탈하는 경향
**액션 아이템**: 초심자 던전 난이도 조정, 실패 시 보상 시스템
### Feature Importance 결과
**중요도 점수별 액션:**
- **0.1 이상** (매우 중요): 즉시 개선 프로젝트 착수
- **0.05-0.1** (중요): 다음 분기 개선 계획에 포함
- **0.01-0.05** (보통): 정기 모니터링 대상
- **0.01 미만** (낮음): 우선순위 후순위
### D0 분석 결과
**차이율별 해석 및 액션:**
```
tutorial_complete:
- D0 평균: 0.23, 잔존 평균: 0.89, 차이: 287%
```
→ 튜토리얼 완료가 리텐션에 결정적 영향
**즉시 액션**: 튜토리얼 완료율 개선 프로젝트
### 가입 패턴 분석 결과
**시간대별 분석:**
```
가입 집중 시간: 20시 (1,250명)
```
→ 저녁 시간대에 가입이 집중됨을 의미
**마케팅 액션**: 해당 시간대 타겟팅 광고 집중
**요일별 분석:**
```
가입 집중 요일: 토요일 (3,200명)
```
→ 주말에 신규 가입이 활발함
**운영 액션**: 주말 이벤트 및 서버 안정성 강화
## 문제 해결 및 최적화
### 일반적인 오류와 해결책
**1. 메모리 부족 오류**
```python
# 청크 단위 처리
chunk_size = 50000
for chunk in pd.read_csv(filepath, chunksize=chunk_size):
process_chunk(chunk)
```
**2. 인코딩 오류**
```python
# UTF-8 인코딩 명시적 지정
df = pd.read_csv(filepath, encoding='utf-8-sig')
```
**3. 성능 최적화**
```python
# 데이터 타입 최적화
df['user_level'] = df['user_level'].astype('int16') # 메모리 절약
df['is_premium'] = df['is_premium'].astype('bool') # 불린 최적화
```
### 대용량 데이터 처리
**샘플링 전략:**
```python
# 층화 샘플링 (각 리텐션 그룹에서 동일 비율 추출)
from sklearn.model_selection import train_test_split
sampled_data, _ = train_test_split(
df,
test_size=0.7, # 30%만 사용
stratify=df['retention_status'], # 층화
random_state=42
)
```
## 비즈니스 임팩트 및 ROI
### 개선 우선순위 매트릭스
```
높은 임팩트 낮은 임팩트
높은 구현비용 [계획 검토] [보류]
낮은 구현비용 [즉시 실행] [빠른 승리]
```
### A/B 테스트 설계
분석 결과를 바탕으로 한 개선안은 반드시 A/B 테스트를 통해 검증:
```python
# 실험 설계 예시
control_group = new_users.sample(frac=0.5, random_state=42)
treatment_group = new_users.drop(control_group.index)
# 개선 효과 측정
improvement = (treatment_retention - control_retention) / control_retention
statistical_power = calculate_power(effect_size, alpha=0.05, sample_size=len(control_group))
```
## 결론 및 향후 개선
`retention_analysis.py` 스크립트는 단순한 데이터 분석을 넘어서, 게임 서비스 개선을 위한 **의사결정 지원 시스템**의 역할을 합니다.
**핵심 가치:**
1. **과학적 접근**: 통계적으로 검증된 방법론으로 신뢰할 수 있는 인사이트 제공
2. **실행 가능성**: 분석 결과가 구체적인 개선 액션으로 연결
3. **확장성**: 새로운 분석 기법과 지표를 쉽게 추가 가능
4. **자동화**: 정기적인 분석과 모니터링을 통한 지속적 개선
5. **시간대 인사이트**: 가입 패턴 분석으로 마케팅/운영 최적화 지원
**2024년 8월 업데이트 내용:**
- **HTML 리포트**: 마크다운에서 전문적인 HTML 형식으로 변경
- **분석 기간 정보**: ISO 8601 형식 `create_time` 기반 자동 추출
- **시간대 분석**: 한국 시간 기준 시간대별/요일별 가입 패턴 분석
- **콘솔로그 분리**: HTML 리포트에서 콘솔로그 제거, 상세 분석 데이터 중심으로 개편
- **데이터 품질 강화**: 표준 시간 형식 지원으로 분석 정확도 향상
**향후 발전 방향:**
- 실시간 대시보드 연동 (가입 패턴 실시간 모니터링)
- 예측 모델 고도화 (딥러닝 활용)
- 개인화된 리텐션 전략 추천 (시간대별 타겟팅)
- 자동화된 A/B 테스트 파이프라인
- 가입 패턴 기반 마케팅 최적화 시스템
정기적인 분석을 통해 게임 개선 효과를 측정하고, 새로운 문제점을 조기에 발견하여 서비스의 지속 가능한 성장에 기여할 수 있습니다.