--- id: wiki-2026-0508-experience-sampling-method title: Experience Sampling Method category: 10_Wiki/Topics status: verified canonical_id: self aliases: [ESM, EMA, Ecological Momentary Assessment, Diary Studies] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [research-methodology, psychology, ux-research, mobile] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: react-native --- # Experience Sampling Method ## 매 한 줄 > **"매 retrospection bias 의 in-the-moment self-report 의 replace"**. Experience Sampling Method (ESM, Csikszentmihalyi & Larson 1987) 매 participants 의 day 의 multiple times 의 random/scheduled prompt, 매 current activity/affect/context 의 record. Mobile-era 매 EMA (Ecological Momentary Assessment) 의 generalize — 매 mental health, UX, productivity research 의 gold standard. ## 매 핵심 ### 매 Why ESM - **Retrospection bias**: 매 "지난주 어땠나" 매 peak-end bias, mood-congruent recall 의 distort. - **Ecological validity**: 매 in-context 매 lab 의 not-replicate. - **Within-subject variance**: 매 person × situation 의 interaction 의 capture. ### 매 Sampling schedules - **Signal-contingent**: 매 random beep 매 day 매 6-8 prompts. - **Interval-contingent**: 매 fixed times (9am/12pm/3pm/6pm). - **Event-contingent**: 매 specific event (meal, exercise) 의 trigger. - **Hybrid**: 매 baseline random + event triggers. ### 매 응용 1. Mood / affect tracking (depression, bipolar). 2. Pain studies (chronic pain). 3. UX product research — feature use in-context. 4. Flow state research (Csikszentmihalyi original). 5. LLM agent behavior tracking — analog 매 process. ## 💻 패턴 ### Mobile prompt scheduler (React Native) ```typescript import * as Notifications from 'expo-notifications'; interface ESMConfig { startHour: number; endHour: number; promptsPerDay: number; minIntervalMinutes: number; } async function schedulePrompts(cfg: ESMConfig, days = 7) { const slots = generateRandomSlots(cfg, days); for (const slot of slots) { await Notifications.scheduleNotificationAsync({ content: { title: 'Quick check-in (30s)', body: 'How are you feeling right now?', data: { promptId: slot.id, scheduledFor: slot.time.toISOString() }, }, trigger: { date: slot.time }, }); } } function generateRandomSlots(cfg: ESMConfig, days: number) { const slots = []; for (let d = 0; d < days; d++) { const dayStart = new Date(); dayStart.setDate(dayStart.getDate() + d); const windowMs = (cfg.endHour - cfg.startHour) * 3600_000; const minGap = cfg.minIntervalMinutes * 60_000; const times: number[] = []; while (times.length < cfg.promptsPerDay) { const candidate = Math.random() * windowMs; if (times.every(t => Math.abs(t - candidate) >= minGap)) { times.push(candidate); } } times.sort((a, b) => a - b).forEach((offset, i) => { const t = new Date(dayStart); t.setHours(cfg.startHour, 0, 0, 0); t.setTime(t.getTime() + offset); slots.push({ id: `${d}-${i}`, time: t }); }); } return slots; } ``` ### Brief response form (PANAS-short, 30s budget) ```typescript interface ESMResponse { promptId: string; respondedAt: Date; latencyMs: number; affect: { valence: number; // -3..+3 arousal: number; // -3..+3 }; activity: string; // dropdown: work | social | rest | exercise | other social: 'alone' | 'with_others'; freeText?: string; } ``` ### Compliance tracking ```typescript function complianceMetrics(responses: ESMResponse[], scheduled: number) { const completed = responses.length; const onTime = responses.filter(r => r.latencyMs < 15 * 60_000).length; const meanLatency = responses.reduce((s, r) => s + r.latencyMs, 0) / completed; return { completionRate: completed / scheduled, // target > 0.7 onTimeRate: onTime / scheduled, // target > 0.5 meanLatencyMin: meanLatency / 60_000, }; } ``` ### Multilevel analysis (within vs between) ```python import statsmodels.formula.api as smf # 매 each row 매 prompt response, 매 participant_id 매 grouping model = smf.mixedlm( 'valence ~ activity + social + time_of_day', data=df, groups=df['participant_id'], re_formula='~time_of_day', ).fit() print(model.summary()) # 매 within-person variance (situation) 매 between-person (trait) 의 separate ``` ### Sliding-window mood detection ```typescript function detectMoodEpisode(responses: ESMResponse[], windowDays = 7, threshold = -1.5) { const sorted = [...responses].sort((a, b) => a.respondedAt.getTime() - b.respondedAt.getTime()); const episodes = []; for (let i = 0; i < sorted.length; i++) { const start = sorted[i].respondedAt; const end = new Date(start.getTime() + windowDays * 86400_000); const window = sorted.filter(r => r.respondedAt >= start && r.respondedAt <= end); if (window.length < 5) continue; const meanV = window.reduce((s, r) => s + r.affect.valence, 0) / window.length; if (meanV < threshold) episodes.push({ start, end, meanV, n: window.length }); } return mergeOverlapping(episodes); } ``` ### Privacy: 매 on-device aggregation ```typescript // 매 raw responses 매 device 의 stay, 매 weekly summary 만 의 server 의 send async function uploadWeeklySummary(responses: ESMResponse[]) { const summary = { week: getCurrentWeek(), n: responses.length, valenceMean: mean(responses.map(r => r.affect.valence)), valenceStd: std(responses.map(r => r.affect.valence)), activityHistogram: histogram(responses.map(r => r.activity)), }; await api.post('/esm/summary', summary); } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Trait measurement (depression baseline) | 매 ESM unnecessary — 매 single questionnaire 매 fine | | Within-day variation 의 question | 매 ESM signal-contingent | | Specific event 매 rare | 매 event-contingent | | Compliance fragile | 매 prompt count 의 reduce, 매 incentive | | Privacy-sensitive (clinical) | 매 on-device aggregation 또는 federated | **기본값**: 매 6-8 prompts/day, 매 14 days, 매 30s response — 매 compliance > 70% 의 target. ## 🔗 Graph - 부모: [[Research-Methodology]] - 변형: [[Ecological-Momentary-Assessment]] - 응용: [[Flow_State|Flow-State]] ## 🤖 LLM 활용 **언제**: 매 in-the-moment subjective state 의 measure. Within-person variance 의 study. Retrospective bias 의 likely. **언제 X**: 매 stable trait. 매 single-shot decision study. 매 intrusive sampling 매 acceptable 의 X. ## ❌ 안티패턴 - **Too many prompts**: 매 12+/day 매 fatigue → compliance crash. - **Long forms**: 매 5min response 매 ecological 의 break. - **Ignoring missing-not-at-random**: 매 prompts during depressive episode 매 skipped — 매 selection bias. - **Cross-sectional analysis 의 hierarchical data**: 매 multilevel model 의 use, 매 OLS 의 std error 의 underestimate. ## 🧪 검증 / 중복 - Verified (Csikszentmihalyi & Larson 1987 JNMD; Shiffman et al. 2008 Ann Rev Clin Psych). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — ESM scheduler + analysis + privacy patterns |