lección 4

Día 3 -- Métricas de producto: DAU, retention, engagement

Calculas las métricas que Marta necesita para inversores: DAU/MAU con tendencia, retención por cohorte D1/D7/D30 y engagement score por usuario.

45 min

### Miércoles, 8:00 AM -- Los datos están listos

Hoy calculas métricas sobre los datos ya cargados. Si lo reproduces en local, parte de `datos/reproducciones_eventos.parquet` para DAU/MAU, retención y engagement (usa `user_id`, `content_id`, `timestamp` y `properties`) cruzado con `datos/usuarios.csv` (`signup_date` o `created_at` para definir las cohortes de registro). Para la conversión free a premium y el churn usa `datos/suscripciones.csv` (`plan_type, status, started_at, ended_at, monthly_amount_eur, cancel_reason`) y, si necesitas ingresos reales, `datos/pagos.csv` (`payment_id, subscription_id, user_id, amount_eur, currency, status, payment_date, payment_method, failure_reason`). Las queries SQL de esta lección usan el esquema PostgreSQL ilustrativo (`playbacks`, `watch_seconds`, `completed`, `registered_at`); trabaja con las columnas reales de los ficheros cuando ejecutes en tu máquina.

El pipeline corrió anoche a las 03:00. Los 3 millones de reproducciones históricas están en S3 como Parquet particionado por fecha. DuckDB tiene vistas configuradas. Es hora de transformar bytes en narrativa. Porque eso es lo que Marta necesita para el viernes: no un dashboard con números, sino una HISTORIA que un inversor pueda seguir y que le haga sacar la chequera.

La historia que los inversores de streaming quieren escuchar tiene tres actos: "La gente viene" (crecimiento DAU/MAU), "La gente se queda" (retención por cohorte) y "La gente se engancha" (engagement creciente). Si las tres curvas van hacía arriba, la conclusión es inevitable: este producto tiene product-market fit y merece inversión para escalar.

### Acto 1: "La gente viene" -- DAU, WAU, MAU

Las métricas de actividad son el primer indicador de salud. Un inversor mira DAU/MAU como un médico mira el pulso: si hay pulso constante y creciente, el paciente está vivo y mejorando. El ratio DAU/MAU (stickiness) indica si el producto es un hábito diario o una visita esporádica.

1-- Cálculo de DAU, WAU, MAU con tendencia
2-- Ejecutar en DuckDB contra las vistas del lake
3
4-- DAU: usuarios únicos que reprodujeron algo cada día
5CREATE OR REPLACE VIEW metric_dau AS
6SELECT
7 event_date,
8 COUNT(DISTINCT user_id) AS dau,
9 -- Media móvil 7 días para suavizar variación diaria
10 AVG(COUNT(DISTINCT user_id)) OVER (
11 ORDER BY event_date
12 ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
13 ) AS dau_7d_avg
14FROM v_playbacks
15WHERE watch_seconds > 30 -- Solo sesiones significativas (> 30s)
16GROUP BY event_date
17ORDER BY event_date;
18
19-- MAU: usuarios únicos en ventana de 30 días rolling
20CREATE OR REPLACE VIEW metric_mau AS
21SELECT
22 event_date,
23 COUNT(DISTINCT user_id) OVER (
24 ORDER BY event_date
25 RANGE BETWEEN INTERVAL '29 days' PRECEDING AND CURRENT ROW
26 ) AS mau_rolling
27FROM (
28 SELECT DISTINCT event_date, user_id
29 FROM v_playbacks
30 WHERE watch_seconds > 30
31)
32GROUP BY event_date
33ORDER BY event_date;
34
35-- Stickiness: DAU / MAU
36SELECT
37 d.event_date,
38 d.dau,
39 m.mau_rolling AS mau,
40 ROUND(d.dau * 100.0 / NULLIF(m.mau_rolling, 0), 1) AS stickiness_pct
41FROM metric_dau d
42JOIN metric_mau m ON d.event_date = m.event_date
43WHERE d.event_date >= '2024-01-01'
44ORDER BY d.event_date;

DAU con media móvil 7 días + stickiness. Solo sesiones > 30s para no inflar con bounces.

La decisión de filtrar por watch_seconds > 30 es deliberada. Un usuario que abre un vídeo y lo cierra en 5 segundos no es "activo" -- es alguien que hizo clic por error o que no le gustó la primera escena. En TaskFlow, Pablo (el PM) te enseñó está lección: "Un usuario activo es alguien que USÓ el producto, no alguien que lo abrió y se fue." Aquí, "usar el producto" significa ver contenido durante al menos 30 segundos.

### Acto 2: "La gente se queda" -- Retención por cohorte

La retención es LA métrica que separa startups con product-market fit de las que no lo tienen. Un inversor sofisticado como Meridian Capital sabe que el crecimiento de MAU puede ser artificial (publicidad pagada). Pero la retención no miente: si los usuarios vuelven después de 7 días sin que les pagues por hacerlo, el producto tiene algo que funciona.

1-- Retención por cohorte semanal: D1, D7, D14, D30
2-- Cohorte = semana de primer playback del usuario
3
4WITH user_first_play AS (
5 -- Fecha del primer playback significativo de cada usuario
6 SELECT
7 user_id,
8 MIN(event_date) AS cohort_date,
9 DATE_TRUNC('week', MIN(event_date))::DATE AS cohort_week
10 FROM v_playbacks
11 WHERE watch_seconds > 30
12 GROUP BY user_id
13),
14user_activity AS (
15 -- Todas las fechas en que cada usuario fue activo
16 SELECT DISTINCT user_id, event_date
17 FROM v_playbacks
18 WHERE watch_seconds > 30
19),
20retention_calc AS (
21 SELECT
22 ufp.cohort_week,
23 COUNT(DISTINCT ufp.user_id) AS cohort_size,
24 COUNT(DISTINCT CASE
25 WHEN ua.event_date = ufp.cohort_date + INTERVAL '1 day'
26 THEN ufp.user_id END) AS retained_d1,
27 COUNT(DISTINCT CASE
28 WHEN ua.event_date BETWEEN ufp.cohort_date + INTERVAL '6 days'
29 AND ufp.cohort_date + INTERVAL '8 days'
30 THEN ufp.user_id END) AS retained_d7,
31 COUNT(DISTINCT CASE
32 WHEN ua.event_date BETWEEN ufp.cohort_date + INTERVAL '13 days'
33 AND ufp.cohort_date + INTERVAL '15 days'
34 THEN ufp.user_id END) AS retained_d14,
35 COUNT(DISTINCT CASE
36 WHEN ua.event_date BETWEEN ufp.cohort_date + INTERVAL '28 days'
37 AND ufp.cohort_date + INTERVAL '32 days'
38 THEN ufp.user_id END) AS retained_d30
39 FROM user_first_play ufp
40 LEFT JOIN user_activity ua ON ufp.user_id = ua.user_id
41 GROUP BY ufp.cohort_week
42)
43SELECT
44 cohort_week,
45 cohort_size,
46 ROUND(retained_d1 * 100.0 / cohort_size, 1) AS retention_d1_pct,
47 ROUND(retained_d7 * 100.0 / cohort_size, 1) AS retention_d7_pct,
48 ROUND(retained_d14 * 100.0 / cohort_size, 1) AS retention_d14_pct,
49 ROUND(retained_d30 * 100.0 / cohort_size, 1) AS retention_d30_pct
50FROM retention_calc
51WHERE cohort_week >= '2023-10-01' -- Últimos 5 meses (cohortes con D30 completo)
52ORDER BY cohort_week;

Retención por cohorte semanal con ventanas flexibles (+-1 día). El dato que cierra rondas.

La ventana de +-1 día en la retención no es un truco -- es realismo. Un usuario "D7" no siempre vuelve exactamente el día 7. Si vuelve el día 6 u 8, sigue siendo retención a la semana. Netflix usa ventanas de +-2 días para sus cohortes internas. Para la presentación a inversores, esto da números más estables sin ser deshonesto.

### Acto 3: "La gente se engancha" -- Engagement Score

El engagement es más difícil de capturar en un solo número. No es solo "cuánto tiempo ven" -- es una combinación de frecuencia (cuántos días a la semana), profundidad (cuánto contenido completan) e intensidad (cuánto tiempo por sesión). Diseñas un engagement score compuesto que pondera estos tres factores:

1-- Engagement Score por usuario (últimos 30 días)
2-- Composición: frecuencia (40%) + profundidad (30%) + intensidad (30%)
3
4WITH user_metrics_30d AS (
5 SELECT
6 user_id,
7 COUNT(DISTINCT event_date) AS active_days,
8 COUNT(*) AS total_plays,
9 SUM(watch_seconds) / 3600.0 AS total_hours,
10 AVG(watch_seconds) / 60.0 AS avg_session_minutes,
11 AVG(CASE WHEN completion_ratio > 0 THEN completion_ratio END) AS avg_completion,
12 COUNT(CASE WHEN completed THEN 1 END) AS titles_completed
13 FROM v_playbacks
14 WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'
15 AND watch_seconds > 30
16 GROUP BY user_id
17),
18scored AS (
19 SELECT
20 user_id,
21 active_days,
22 total_plays,
23 total_hours,
24 avg_session_minutes,
25 avg_completion,
26 titles_completed,
27 -- Frecuencia: días activos / 30 (max 1.0)
28 LEAST(active_days / 30.0, 1.0) AS freq_score,
29 -- Profundidad: completion rate promedio (ya está entre 0 y 1)
30 COALESCE(avg_completion, 0) AS depth_score,
31 -- Intensidad: minutos por sesión normalizado (30 min = 1.0)
32 LEAST(avg_session_minutes / 30.0, 1.0) AS intensity_score
33 FROM user_metrics_30d
34)
35SELECT
36 user_id,
37 active_days,
38 total_hours,
39 avg_completion,
40 -- Engagement Score: ponderado
41 ROUND(
42 (freq_score * 0.4 + depth_score * 0.3 + intensity_score * 0.3) * 100,
43 1
44 ) AS engagement_score,
45 -- Segmento basado en score
46 CASE
47 WHEN (freq_score * 0.4 + depth_score * 0.3 + intensity_score * 0.3) >= 0.7
48 THEN 'power_user'
49 WHEN (freq_score * 0.4 + depth_score * 0.3 + intensity_score * 0.3) >= 0.4
50 THEN 'regular'
51 WHEN (freq_score * 0.4 + depth_score * 0.3 + intensity_score * 0.3) >= 0.15
52 THEN 'casual'
53 ELSE 'at_risk'
54 END AS user_segment
55FROM scored
56ORDER BY engagement_score DESC;

Engagement score compuesto: frecuencia (40%) + profundidad (30%) + intensidad (30%).

El engagement score te permite segmentar usuarios en 4 grupos: power users (>70, los evangelistas), regulars (40-70, el core), casuals (15-40, oportunidad de activación) y at-risk (<15, candidatos a churn). Para Marta, la distribución de estos segmentos es una historia poderosa: "El 20% de nuestros usuarios son power users que ven más de 10 horas al mes y completan el 75% del contenido que empiezan."

La segmentación también es accionable: los power users son tus evangelistas (lánzales un programa de referidos). Los regulares son tu core (no los molestes, solo mejora el contenido). Los casuals son tu oportunidad (emails de contenido personalizado para reactivarlos). Los at-risk son tu alerta temprana (si crecen, tienes un problema de producto).

1-- Resumen ejecutivo de segmentos para el dashboard
2SELECT
3 segment,
4 COUNT(*) AS users,
5 ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 1) AS pct,
6 ROUND(AVG(engagement_score), 1) AS avg_score,
7 ROUND(AVG(total_hours), 1) AS avg_hours_monthly,
8 ROUND(AVG(active_days), 1) AS avg_days_active
9FROM (
10 -- (subquery del engagement score anterior)
11 SELECT user_id, engagement_score, total_hours, active_days,
12 CASE
13 WHEN engagement_score >= 70 THEN 'Power User'
14 WHEN engagement_score >= 40 THEN 'Regular'
15 WHEN engagement_score >= 15 THEN 'Casual'
16 ELSE 'At Risk'
17 END AS segment
18 FROM user_engagement_scores
19)
20GROUP BY segment
21ORDER BY avg_score DESC;
22
23-- Resultado esperado:
24-- Power User | 2.940 | 19.6% | 81.2 | 12.4h | 21.3 días
25-- Regular | 5.250 | 35.0% | 53.7 | 5.8h | 10.1 días
26-- Casual | 4.560 | 30.4% | 27.3 | 2.1h | 3.8 días
27-- At Risk | 2.250 | 15.0% | 8.4 | 0.4h | 1.2 días

Distribución de segmentos: 55% engaged (power+regular) es una señal fuerte para inversores.

### Crecimiento MoM -- la tendencia que importa

1-- Crecimiento Month-over-Month de MAU
2WITH monthly_mau AS (
3 SELECT
4 DATE_TRUNC('month', event_date)::DATE AS month,
5 COUNT(DISTINCT user_id) AS mau
6 FROM v_playbacks
7 WHERE watch_seconds > 30
8 GROUP BY DATE_TRUNC('month', event_date)
9)
10SELECT
11 month,
12 mau,
13 LAG(mau) OVER (ORDER BY month) AS prev_month_mau,
14 ROUND(
15 (mau - LAG(mau) OVER (ORDER BY month)) * 100.0
16 / NULLIF(LAG(mau) OVER (ORDER BY month), 0),
17 1
18 ) AS growth_mom_pct
19FROM monthly_mau
20WHERE month >= '2023-06-01'
21ORDER BY month;
22
23-- Resultado esperado (últimos meses):
24-- 2024-01: 12.400 MAU (+6.8% MoM)
25-- 2024-02: 13.600 MAU (+9.7% MoM)
26-- 2024-03: 15.100 MAU (+11.0% MoM) <- tendencia acelerando

Crecimiento MoM acelerando: la señal que todo VC quiere ver.

Un crecimiento MoM del 8-11% sin gasto significativo en marketing es una señal fuerte de producto orgánico. Marta te confirma que el 80% del crecimiento viene de referidos y búsqueda orgánica. Eso es exactamente lo que Meridian Capital quiere escuchar: "el producto crece solo porque es bueno".

### Resumen del Día 3 (mañana)

  • Calculaste DAU/MAU con media móvil 7 días y stickiness ratio (~14%)
  • Implementaste retención por cohorte semanal: D1, D7, D14, D30 con ventanas flexibles
  • Diseñaste engagement score compuesto (frecuencia + profundidad + intensidad)
  • Segmentaste usuarios: power (20%), regular (35%), casual (30%), at-risk (15%)
  • Verificaste crecimiento MoM acelerando: 6.8% -> 9.7% -> 11.0%
  • Tienes los tres actos de la narrativa listos: "vienen, se quedan, se enganchan"

## ejercicios

[01]

Calcular DAU/MAU con stickiness y tendencia

Implementa las queries que calculan DAU diario, MAU rolling de 30 días y el ratio de stickiness. Incluye media móvil de 7 días para suavizar la variación y calcula el crecimiento WoW.

Cargando editor...
[02]

Retención por cohorte con ventana flexible

Implementa el cálculo de retención D1/D7/D30 por cohorte mensual de registro. Usa ventanas flexibles de +-1 día para D7 y +-2 días para D30. El resultado debe ser la tabla de cohortes que Marta mostrará a Meridian Capital.

Cargando editor...
[03]

Métricas de monetización: conversión y churn

Los inversores quieren ver que el modelo freemium funciona. Calcula la tasa de conversión free->premium mensual y el churn rate mensual de suscriptores premium usando las tablas de subscriptions y users.

Cargando editor...
[04]

Engagement score y segmentación de usuarios

Implementa en Python el cálculo del engagement score compuesto y la segmentación de usuarios en power/regular/casual/at_risk. Genera también las estadísticas agregadas por segmento para el dashboard.

Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...