--- id: wiki-2026-0508-data-driven-personalization title: Data-Driven Personalization category: 10_Wiki/Topics status: verified canonical_id: self aliases: [personalization, dynamic-personalization, player-segmentation] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [data, personalization, segmentation, ml, mobile-game] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: python framework: feature-store-ml --- # Data-Driven Personalization ## 매 한 줄 > **"매 player 의 behavior data 로 매 content / offer / difficulty 의 individual tuning"**. 매 segment 단위 → 매 ML-driven individual 단위 의 매 evolution. 매 2026 standard 는 매 real-time feature store + 매 contextual bandit + 매 explainable rule overlay. ## 매 핵심 ### 매 segmentation tier - **Static segment**: 매 country, install_source. - **Behavior segment**: 매 spender / dolphin / minnow / F2P. - **Lifecycle**: 매 new / engaged / churning / churned. - **ML cluster**: 매 k-means / autoencoder embedding. ### 매 personalization surface - **Offer pricing**: 매 player-specific bundle. - **Difficulty**: 매 adaptive level. - **Content order**: 매 onboarding sequence. - **Push timing**: 매 individual best-time. ### 매 응용 1. 매 LTV uplift (매 10-30%). 2. 매 retention curve flattening. 3. 매 cohort-specific event design. ## 💻 패턴 ### Player feature vector ```python from dataclasses import dataclass from typing import Literal @dataclass class PlayerFeatures: days_since_install: int sessions_7d: int sessions_30d: int spend_total: float spend_30d: float last_spend_days: int avg_session_min: float progression_level: int cohort: Literal["new", "engaged", "churning", "churned"] country: str def derive_cohort(p: PlayerFeatures) -> str: if p.days_since_install < 7: return "new" if p.sessions_7d == 0: return "churned" if p.sessions_7d < p.sessions_30d / 8: return "churning" return "engaged" ``` ### Contextual bandit (offer selection) ```python import numpy as np class LinUCB: def __init__(self, n_arms: int, n_features: int, alpha: float = 1.0): self.A = [np.eye(n_features) for _ in range(n_arms)] self.b = [np.zeros(n_features) for _ in range(n_arms)] self.alpha = alpha def select(self, x: np.ndarray) -> int: scores = [] for a in range(len(self.A)): A_inv = np.linalg.inv(self.A[a]) theta = A_inv @ self.b[a] ucb = theta @ x + self.alpha * np.sqrt(x @ A_inv @ x) scores.append(ucb) return int(np.argmax(scores)) def update(self, arm: int, x: np.ndarray, reward: float): self.A[arm] += np.outer(x, x) self.b[arm] += reward * x ``` ### Adaptive difficulty (player skill estimate) ```python def estimate_skill(recent_attempts: list[dict]) -> float: """recent_attempts: [{success: bool, level_difficulty: float}]""" if not recent_attempts: return 0.5 total_w = sum(0.9 ** i for i in range(len(recent_attempts))) skill = sum( (a["level_difficulty"] if a["success"] else a["level_difficulty"] - 0.2) * (0.9 ** i) for i, a in enumerate(recent_attempts) ) / total_w return max(0.0, min(1.0, skill)) def next_difficulty(skill: float, target_winrate: float = 0.65) -> float: # Want challenge slightly above skill return skill + (1 - target_winrate) * 0.3 ``` ### Real-time feature store query ```python from datetime import datetime class FeatureStore: def __init__(self, redis_client, warehouse_client): self.redis = redis_client self.warehouse = warehouse_client async def get_player_features(self, player_id: str) -> PlayerFeatures: # Hot features from Redis hot = await self.redis.hgetall(f"player:{player_id}:hot") # Cold features from warehouse (cached) cold = await self.warehouse.query( f"SELECT * FROM player_cold WHERE id = '{player_id}'" ) return PlayerFeatures(**{**cold, **hot}) ``` ### Explainable overlay (rule + ML) ```python def select_offer_with_guardrails(p: PlayerFeatures, ml_pick: int, offers: list) -> int: # Guardrails override ML if p.spend_total == 0 and offers[ml_pick].price > 9.99: return offers.index(STARTER_PACK_499) # never expensive to non-spenders if p.cohort == "churning": return offers.index(WIN_BACK_OFFER) if p.country in HIGH_RISK_COUNTRIES and offers[ml_pick].price > 4.99: return offers.index(LOW_PRICE_DEFAULT) return ml_pick ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | 매 small data | Static segment + rules | | 매 medium data | Behavior segment + A/B | | 매 large data | ML cluster + contextual bandit | | 매 regulated market | Rule guardrails 의 mandatory | **기본값**: 매 segment + bandit + 매 rule guardrails 의 layered. ## 🔗 Graph - 부모: [[Live-Ops]] - 변형: [[Dynamic Offers]] · [[Adaptive-Difficulty]] - 응용: [[Game_Monetization_Strategy]] · [[Capybara GO!]] - Adjacent: [[CPI (Cost Per Install)]] · [[Gacha Mechanics Analysis]] ## 🤖 LLM 활용 **언제**: 매 segmentation design, bandit setup, feature engineering. **언제 X**: 매 cold-start product — 매 data 부족. ## ❌ 안티패턴 - **Predatory targeting**: 매 vulnerable player 의 매 high-spend offer. - **Black-box only**: 매 explainability 없음 → 매 regulator + designer 둘 다 lost. - **Stale features**: 매 hourly batch → 매 real-time signal miss. - **Over-segmentation**: 매 sample size 부족. ## 🧪 검증 / 중복 - Verified (Unity LiveOps 2025 report, GameAnalytics Personalization Whitepaper). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — data-driven personalization with bandit + guardrails. |