lección 7

Día 5 -- A/B testing y la presentación a Meridian Capital

Diseñas el framework de A/B testing con significancia estadística. Acompañas a Marta a la presentación y el dashboard cuenta la historia correcta.

40 min

### Viernes, 7:30 AM -- El día de la verdad

El framework de A/B testing de hoy funciona sobre parámetros (baseline, efecto mínimo detectable, DAU) y no lee ficheros directamente. Esos parámetros salen de las métricas que calculaste antes con `datos/reproducciones_eventos.parquet` y `datos/suscripciones.csv`: el baseline de completion (~55%) y el DAU (~2100) son las entradas que usarás. Si quieres recalcularlos para tu propio experimento, parte de esos ficheros guardados en `datos/`.

Hoy es viernes. A las 11:00 Marta se sienta frente a tres partners de Meridian Capital con tu dashboard proyectado en la pantalla. Pero antes de eso, tienes 3 horas para completar la última pieza del puzzle: un framework de A/B testing que demuestre a los inversores que StreamVibe no solo mide -- sino que experimenta de forma rigurosa para mejorar.

Los VCs sofisticados ya no se conforman con métricas bonitas. Quieren ver que el equipo tiene una cultura de experimentación: "¿Cómo sabéis que las mejoras son reales y no ruido estadístico?" Si puedes mostrar un framework de A/B testing funcionando -- aunque sea con un solo experimento -- demuestras madurez analítica que poca startup pre-Serie A tiene.

### ¿Por qué A/B testing en una startup de 15K usuarios?

La objeción habitual es "somos muy pequeños para hacer A/B tests". Es falsa. Con 15K MAU y ~2.100 DAU, puedes hacer tests que alcanzan significancia estadística en 7-14 días para efectos del 10% o más. No es Netflix con millones de usuarios donde puedes detectar mejoras del 0.5% -- pero sí puedes validar decisiones grandes como "¿el onboarding nuevo retiene más?" o "¿el autoplay entre episodios aumenta el watch time?"

La razón estratégica para tener A/B testing desde el día 1 es cultural, no técnica. Si el equipo de producto se acostumbra a lanzar features sin validar, cuando tengan 150K usuarios seguirán sin validar -- pero ahora con consecuencias mucho mayores. Establecer la cultura de "medimos antes de decidir" cuando eres pequeño es infinitamente más fácil que implantarla después.

Además, los inversores lo saben. Cuando Meridian Capital pregunta "¿hacéis A/B testing?", no preguntan si podéis detectar efectos del 0.1%. Preguntan: "¿tenéis una cultura de experimentación? ¿tomáis decisiones de producto basadas en evidencia o en opinión del fundador?" Tener un framework funcionando, aunque sea simple, demuestra madurez analítica.

### El framework de A/B testing

El framework tiene 4 componentes: asignación de usuarios a variantes, recolección de métricas por variante, cálculo de significancia estadística y decisión (ship/kill/continue). Lo implementas como un módulo Python que puede correr manualmente o integrase con el pipeline diario.

1# Framework de A/B Testing para StreamVibe
2# Componente 1: Diseño del experimento
3
4from dataclasses import dataclass
5from typing import Optional
6import hashlib
7
8
9@dataclass
10class Experiment:
11 """Definición de un experimento A/B."""
12 id: str
13 name: str
14 description: str
15 metric: str # La métrica principal que mides
16 hypothesis: str # "Si hacemos X, entonces Y aumentará en Z%"
17 min_sample_size: int # Usuarios mínimos por variante
18 min_days: int # Duración mínima
19 variants: list[str] # ['control', 'treatment'] o más
20 traffic_split: list[float] # [0.5, 0.5] para 50/50
21
22
23def assign_user_to_variant(
24 user_id: int,
25 experiment_id: str,
26 variants: list[str],
27 traffic_split: list[float]
28) -> str:
29 """Asigna un usuario a una variante de forma determinística.
30
31 Usa hash(user_id + experiment_id) para que:
32 - El mismo usuario siempre vea la misma variante
33 - La asignación sea uniforme sin base de datos
34 - Diferentes experimentos tengan asignaciones independientes
35 """
36 hash_input = f"{user_id}:{experiment_id}"
37 hash_value = int(hashlib.md5(hash_input.encode()).hexdigest(), 16)
38 normalized = (hash_value % 10000) / 10000.0 # 0.0 a 1.0
39
40 cumulative = 0.0
41 for i, split in enumerate(traffic_split):
42 cumulative += split
43 if normalized < cumulative:
44 return variants[i]
45
46 return variants[-1] # Fallback al último

Asignación determinística con hash: sin base de datos, sin estado, reproducible.

1# Componente 2: Análisis de significancia estadística
2
3import numpy as np
4from scipy import stats
5from dataclasses import dataclass
6
7
8@dataclass
9class ABTestResult:
10 """Resultado del análisis de un A/B test."""
11 experiment_id: str
12 control_mean: float
13 treatment_mean: float
14 relative_lift: float # (treatment - control) / control * 100
15 p_value: float
16 confidence_level: float # 1 - p_value
17 is_significant: bool # p_value < 0.05
18 sample_size_control: int
19 sample_size_treatment: int
20 recommendation: str # 'ship', 'kill', 'continue'
21
22
23def analyze_continuous_metric(
24 control_values: list[float],
25 treatment_values: list[float],
26 alpha: float = 0.05
27) -> ABTestResult:
28 """Analiza un A/B test para métricas continuas (watch_time, sessions).
29 Usa t-test de Welch (no asume varianzas iguales).
30 """
31 control = np.array(control_values)
32 treatment = np.array(treatment_values)
33
34 control_mean = control.mean()
35 treatment_mean = treatment.mean()
36 relative_lift = (treatment_mean - control_mean) / control_mean * 100
37
38 # Welch's t-test (dos colas)
39 t_stat, p_value = stats.ttest_ind(control, treatment, equal_var=False)
40
41 is_significant = p_value < alpha
42
43 # Recomendación
44 if not is_significant:
45 recommendation = 'continue' if len(control) < 1000 else 'kill'
46 elif relative_lift > 0:
47 recommendation = 'ship'
48 else:
49 recommendation = 'kill'
50
51 return ABTestResult(
52 experiment_id="",
53 control_mean=round(control_mean, 3),
54 treatment_mean=round(treatment_mean, 3),
55 relative_lift=round(relative_lift, 2),
56 p_value=round(p_value, 4),
57 confidence_level=round((1 - p_value) * 100, 1),
58 is_significant=is_significant,
59 sample_size_control=len(control),
60 sample_size_treatment=len(treatment),
61 recommendation=recommendation,
62 )
63
64
65def analyze_conversion_metric(
66 control_conversions: int,
67 control_total: int,
68 treatment_conversions: int,
69 treatment_total: int,
70 alpha: float = 0.05
71) -> ABTestResult:
72 """Analiza un A/B test para métricas de conversión (% que completa, % que vuelve).
73 Usa chi-squared test.
74 """
75 # Tabla de contingencia
76 table = np.array([
77 [control_conversions, control_total - control_conversions],
78 [treatment_conversions, treatment_total - treatment_conversions]
79 ])
80
81 chi2, p_value, dof, expected = stats.chi2_contingency(table)
82
83 control_rate = control_conversions / control_total
84 treatment_rate = treatment_conversions / treatment_total
85 relative_lift = (treatment_rate - control_rate) / control_rate * 100
86
87 is_significant = p_value < alpha
88
89 if not is_significant:
90 recommendation = 'continue' if control_total < 500 else 'kill'
91 elif relative_lift > 0:
92 recommendation = 'ship'
93 else:
94 recommendation = 'kill'
95
96 return ABTestResult(
97 experiment_id="",
98 control_mean=round(control_rate, 4),
99 treatment_mean=round(treatment_rate, 4),
100 relative_lift=round(relative_lift, 2),
101 p_value=round(p_value, 4),
102 confidence_level=round((1 - p_value) * 100, 1),
103 is_significant=is_significant,
104 sample_size_control=control_total,
105 sample_size_treatment=treatment_total,
106 recommendation=recommendation,
107 )

Análisis estadístico: t-test de Welch para métricas continuas, chi-squared para conversión.

### El primer experimento: autoplay entre episodios

Daniel ya tenía implementado un feature flag para autoplay (reproducir el siguiente episodio automáticamente tras 5 segundos de cuenta atrás). Estaba desactivado porque "no sabíamos si los usuarios lo querían o les molestaba". Perfecto: es tu primer A/B test. Hipótesis: "Si activamos autoplay entre episodios de series, el watch time por sesión aumentará al menos un 15% porque reduce la fricción entre episodios."

Configuras el experimento: 50% de usuarios (asignados por hash) ven autoplay activado, 50% siguen con el comportamiento actual. Métricas que rastrear: watch_time por sesión (primaria), completion_rate de series (secundaria), tasa de skip del autoplay (guardrail -- si > 60% de skips, el feature molesta).

### 10:30 AM -- Preparando la presentación

Marta te pide 10 minutos para repasar el dashboard antes de la reunión. Te sientas con ella en la sala y recorren las 3 pantallas:

  1. 01.Pantalla 1 -- KPIs Hero: "15.100 MAU, creciendo al 11% mensual. Stickiness del 14%. Retención D7 del 38%." Marta práctica: "Nuestros usuarios vuelven. No es crecimiento inflado con marketing -- es producto."
  2. 02.Pantalla 2 -- Engagement: "El 55% de nuestros usuarios son regulars o power users. Watch time medio de 31 minutos por sesión. El contenido se termina en un 42% de los casos -- vs. 30% de media en plataformas generalistas." Marta práctica: "Nuestra curación funciona. La gente no hace zapping -- se sienta a ver."
  3. 03.Pantalla 3 -- Contenido: "Los documentales de true crime y series cortas son nuestro sweet spot: 68% de completion, 3x más ROI por euro de licencia. Nuestra estrategia de contenido está validada con datos." Marta práctica: "Sabemos exactamente qué contenido comprar y por qué."

Marta te mira y dice: "Hace 5 días no teníamos ni un número real. Ahora tengo una historia completa que contar con datos de 14 meses detrás. Si no cierro está ronda, no es por falta de métricas." Se levanta, se alisa la chaqueta y se va a la sala de reuniones.

### 11:00 AM -- La presentación a Meridian Capital

No estás en la sala (Marta decidió que era mejor ir sola con Daniel), pero a las 12:15 te llega un mensaje por Slack:

Marta (Slack, 12:15): "Han pedido ver el dashboard EN VIVO. Les he enseñado las cohortes y el crecimiento MoM y se han mirado entre ellos con cara de aprobación. Preguntas: cómo calculamos retention (les he dicho ventana +-1 día y han asentido), qué stack usamos (les ha encantado que gastemos 12 EUR/mes en vez de 400), y si tenemos A/B testing (les he enseñado el framework del autoplay). Nos han pedido un data room para la due diligence. Esto pinta MUY bien. Gracias."

A las 14:00 Marta sale de la sala con una sonrisa: "No es oficial todavía, pero me han dicho que van a preparar un term sheet la semana que viene. Serie A de 4M EUR. La mitad del mérito es del dashboard -- han visto que tomamos decisiones con datos, no con intuición. Exactamente la señal que buscaban."

Lo que acabas de hacer en 5 días: pasar de CERO infraestructura de datos a un dashboard que ayuda a cerrar una ronda de 4M EUR. No porque el dashboard sea bonito -- sino porque los datos cuentan una historia real, verificable, y que demuestra que el producto funciona. Eso es lo que un senior data engineer aporta a una startup.

### Lo que viene: la hoja de ruta de datos post-Serie A

  1. 01.Semana 2: Event tracking real en el reproductor (ya no dependemos de la tabla playbacks legacy)
  2. 02.Mes 1: Contratar un analista de datos -- Sofía necesita soporte continuo para decisiones de contenido
  3. 03.Mes 2: Migrar cron -> Airflow cuando tengamos > 10 pipelines
  4. 04.Mes 3: Implementar el A/B testing como parte del ciclo de producto (1 test por sprint)
  5. 05.Mes 4: Evaluar DuckDB -> Redshift Serverless si el volumen lo justifica
  6. 06.Mes 6: Recomendaciones v2 con modelo de embeddings (si contratamos ML engineer)

### Resumen del Día 5

  • Diseñaste framework de A/B testing con asignación determinística y análisis estadístico
  • Configuraste el primer experimento: autoplay entre episodios (t-test + chi-squared)
  • Preparaste a Marta para la presentación: 3 pantallas con narrativa secuencial
  • La presentación a Meridian Capital fue un éxito: term sheet para Serie A de 4M EUR
  • Documentaste hoja de ruta de datos para los próximos 6 meses post-ronda
  • En 5 días fuiste de CERO a una infraestructura de datos que aportó valor directo al negocio

## ejercicios

[01]

Framework completo de A/B testing

Implementa el framework de A/B testing para StreamVibe: asignación determinística de usuarios a variantes, cálculo de tamaño de muestra necesario, y análisis de resultados con chi-squared test para métricas de conversión.

Cargando editor...
[02]

Diseñar el experimento de autoplay

Diseña el experimento completo de autoplay: hipótesis, métricas, tamaño de muestra, duración estimada y criterios de éxito/fallo. Genera el documento de diseño que presentarías a Marta y Daniel.

Cargando editor...
[03]

Calculadora de tamaño de muestra y viabilidad

Implementa una herramienta que calcule cuántos usuarios necesitas y cuántos días tardará un A/B test dado el DAU de StreamVibe, el baseline y el efecto mínimo detectable.

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...