Difference-in-Differences анализ

Senior Python SaaS

Условие задания

**Контекст:** SaaS-компания запустила новый onboarding-флоу для пользователей из одного региона (treatment), оставив старый для остальных (control). Интервенция произошла на неделе 10.

**Данные:** DataFrame `weekly_metrics` — колонки: `region_id`, `is_treatment` (0/1), `week` (1–20), `active_users`, `revenue`, `retention_7d`.

**Задание:**
1. Проверьте допущение параллельных трендов (parallel trends) на pre-period данных
2. Проведите Difference-in-Differences анализ с помощью OLS-регрессии
3. Оцените эффект интервенции на active_users, revenue и retention_7d

Пример данных

Структура для ориентира — реальные значения из эталонного решения.

import pandas as pd
import numpy as np
import statsmodels.formula.api as smf

np.random.seed(42)
weeks = 20
intervention_week = 10
n_regions = 40

rows = []
for rid in range(n_regions):
    is_treat = 1 if rid < 10 else 0  # 10 treatment, 30 control
    base_users = np.random.normal(1000, 100)
    base_revenue = base_users * np.random.uniform(8, 12)

    for w in range(1, weeks + 1):
        trend = w * 15  # общий тренд
        noise = np.random.normal(0, 50)

        # Эффект интервенции: +120 active_users, +8% revenue
        effect_users = 120 if (is_treat and w >= intervention_week) else 0
        effect_revenue_mult = 1.08 if (is_treat and w >= intervention_week) else 1.0

        active = base_users + trend + noise + effect_users
        revenue = (base_revenue + trend * 10 + noise * 8) * effect_revenue_mult
        ret_7d = np.clip(0.35 + 0.001 * w + 0.03 * is_treat * (w >= intervention_week)
                         + np.random.normal(0, 0.02), 0, 1)

        rows.append({
            'region_id': rid, 'is_treatment': is_treat, 'week': w,
            'active_users': int(active), 'revenue': round(revenue, 2),
            'retention_7d': round(ret_7d, 4),
        })

df = pd.DataFrame(rows)
df['post'] = (df['week'] >= intervention_week).astype(int)
df['treat_x_post'] = df['is_treatment'] * df['post']

# === 1. Проверка параллельных трендов (pre-period) ===
pre = df[df['week'] < intervention_week].copy()

trend_check = smf.ols('active_users ~ week * is_treatment', data=pre).fit()
print("=== Проверка параллельных трендов (pre-period) ===")
print(f"Interaction (week × treatment) p-value: {trend_check.pvalues['week:is_treatment']:.4f}")
print(f"Параллельные тренды: {'Подтверждены ✓' if trend_check.pvalues['week:is_treatment'] > 0.05 else 'Нарушены ✗'}")

# === 2. DiD регрессия ===
print("\n=== DiD: Active Users ===")
model_users = smf.ols('active_users ~ is_treatment + post + treat_x_post', data=df).fit()
print(model_users.summary().tables[1])
print(f"\nDiD эффект (β3): {model_users.params['treat_x_post']:.1f} active users")
print(f"p-value: {model_users.pvalues['treat_x_post']:.4f}")

print("\n=== DiD: Revenue ===")
model_rev = smf.ols('revenue ~ is_treatment + post + treat_x_post', data=df).fit()
print(f"DiD эффект: {model_rev.params['treat_x_post']:.1f} руб.")
print(f"p-value: {model_rev.pvalues['treat_x_post']:.4f}")

print("\n=== DiD: Retention 7d ===")
model_ret = smf.ols('retention_7d ~ is_treatment + post + treat_x_post', data=df).fit()
print(f"DiD эффект: {model_ret.params['treat_x_post']*100:.2f} п.п.")
print(f"p-value: {model_ret.pvalues['treat_x_post']:.4f}")

# === 3. Визуальная проверка (средние по неделям) ===
agg = df.groupby(['week', 'is_treatment'])['active_users'].mean().reset_index()
pivot_agg = agg.pivot(index='week', columns='is_treatment', values='active_users')
pivot_agg.columns = ['Control', 'Treatment']
print("\nСредние active_users по неделям (выборочно):")
print(pivot_agg.loc[[1, 5, 9, 10, 15, 20]].round(0))

Темы

pandas statsmodels diff-in-diff причинный вывод OLS параллельные тренды

Подсказки

Все тестовые задания →

Частые вопросы

Какой уровень знаний нужен для задачи "Difference-in-Differences анализ"?

Это задание для уровня Senior. Senior-уровень — глубокое понимание темы, опыт решения нестандартных задач, обсуждение trade-off на собеседовании.

На каких собеседованиях встречается такая задача?

Подобные задания в категории «Python» регулярно дают на собеседованиях аналитика данных в Яндекс, Сбер, Ozon, Авито, Тинькофф, Wildberries, T-Bank, X5, ВТБ и других крупных IT-компаниях. Тематика: pandas, statsmodels, diff-in-diff, причинный вывод, OLS.

Сколько времени даётся на решение?

На реальном собеседовании на подобную задачу отводится 30-60 минут с обсуждением подходов, оптимизаций и trade-off. Для тренировки рекомендуем сначала решить самостоятельно, потом сверить с эталонным решением и подсказками.

Где ещё потренироваться по теме «Python»?

На zasqlpython.ru есть 482 Python задачи с проверкой через Pyodide, конспекты Python и pandas, AI мок-собеседование с разбором ваших ответов.

← Все задания