lección 5

Día 3 (tarde) -- Modelo analítico de contenido

Respondes la pregunta de Sofía: ¿qué contenido funciona y por qué? Analizas engagement por género, duración y tipo. Diseñas el content performance score.

45 min

### Miércoles, 14:00 -- La pregunta de Sofía

Para el análisis de contenido de Sofía usa `datos/catalogo.csv` (`content_id, title, content_type, genre_primary, genre_secondary, release_year, duration_minutes, season_count, episode_count, is_original, maturity_rating`) cruzado con `datos/reproducciones_eventos.parquet` (`user_id, content_id, timestamp, properties`). Los costes de licencia para el ROI salen de `datos/costes_licencias.xlsx`: es un Excel hecho a mano, con typos en los títulos respecto a `catalogo.csv`, importes en formato europeo (€ con coma decimal), fechas en `DD/MM/YYYY`, packs de varios títulos y 3 costes vacíos; tendrás que limpiarlo y casarlo con el catálogo por título de forma aproximada. Ojo: el catálogo real usa `genre_primary` y `duration_minutes`, no el `genre` ni `duration_seconds` del esquema PostgreSQL ilustrativo que aparece en las queries de diseño.

Después de comer, Sofía te pilla en la cocina: "He oído que ya tienes datos funcionando. ¿Puedes ayudarme con algo? Tengo que decidir en qué gastar 200K EUR en licencias de contenido para el Q2 y literalmente no tengo ni idea de qué funciona mejor en nuestra plataforma. ¿Comedia o drama? ¿Series cortas o películas largas? ¿Documentales de naturaleza o true crime? Cualquier dato que me des es mejor que lo que tengo ahora, que es mi intuición."

Esta es la pregunta de negocio más interesante de la semana. Para Marta, las métricas de producto cuentan una historia de tracción. Para Sofía, el análisis de contenido responde una pregunta operativa concreta: dónde invertir 200K EUR. Si le das la respuesta correcta, StreamVibe compra el contenido que maximiza engagement y retención. Si se equivoca, quema presupuesto en títulos que nadie ve.

### El modelo de performance de contenido

Necesitas un framework que evalúe cada pieza de contenido en múltiples dimensiones. No basta con "cuántas veces se vio" -- una película mala puede tener muchos plays (por curiosidad o marketing) pero poca retención. El verdadero indicador de que un contenido funciona es: ¿la gente lo termina? ¿vuelve al día siguiente? ¿lo recomienda (proxied por si otros usuarios con patrones similares también lo ven)?

1-- Content Performance Score: evalúa cada título por engagement real
2
3WITH content_stats AS (
4 SELECT
5 c.content_id,
6 c.title,
7 c.content_type,
8 c.genre,
9 c.duration_seconds,
10 c.duration_seconds / 60 AS duration_minutes,
11 c.rating_imdb,
12 c.license_cost_eur,
13 COUNT(p.playback_id) AS total_plays,
14 COUNT(DISTINCT p.user_id) AS unique_viewers,
15 AVG(p.watch_seconds) AS avg_watch_seconds,
16 AVG(p.watch_seconds * 1.0 / NULLIF(c.duration_seconds, 0)) AS avg_completion,
17 SUM(CASE WHEN p.completed THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS completion_pct,
18 SUM(p.watch_seconds) / 3600.0 AS total_watch_hours
19 FROM content c
20 LEFT JOIN playbacks p ON c.content_id = p.content_id
21 WHERE p.started_at >= CURRENT_DATE - INTERVAL '90 days'
22 GROUP BY c.content_id, c.title, c.content_type, c.genre,
23 c.duration_seconds, c.rating_imdb, c.license_cost_eur
24),
25with_scores AS (
26 SELECT
27 *,
28 -- Reach score: qué porcentaje del MAU lo vio (normalizado)
29 unique_viewers * 1.0 / (SELECT COUNT(DISTINCT user_id) FROM playbacks
30 WHERE started_at >= CURRENT_DATE - INTERVAL '90 days') AS reach_ratio,
31 -- ROI: horas de watch time por euro de licencia
32 CASE WHEN license_cost_eur > 0
33 THEN total_watch_hours / license_cost_eur
34 ELSE 0 END AS hours_per_eur
35 FROM content_stats
36 WHERE total_plays >= 10 -- Mínimo 10 reproducciones para ser evaluable
37)
38SELECT
39 content_id,
40 title,
41 content_type,
42 genre,
43 duration_minutes,
44 unique_viewers,
45 completion_pct,
46 total_watch_hours,
47 hours_per_eur,
48 -- Content Performance Score (0-100)
49 ROUND(
50 (LEAST(reach_ratio / 0.05, 1.0) * 30 + -- Alcance (30%)
51 LEAST(completion_pct / 80.0, 1.0) * 40 + -- Finalización (40%)
52 LEAST(hours_per_eur / 2.0, 1.0) * 30) -- ROI (30%)
53 , 1) AS performance_score
54FROM with_scores
55ORDER BY performance_score DESC
56LIMIT 50;

Content Performance Score: alcance (30%) + finalización (40%) + ROI por euro (30%).

### Análisis por género -- ¿comedia o drama?

1-- Rendimiento por género: la respuesta a "¿comedia o drama?"
2SELECT
3 c.genre,
4 COUNT(DISTINCT c.content_id) AS titles_available,
5 COUNT(DISTINCT p.user_id) AS unique_viewers,
6 COUNT(p.playback_id) AS total_plays,
7 ROUND(AVG(p.watch_seconds) / 60.0, 1) AS avg_watch_minutes,
8 ROUND(SUM(CASE WHEN p.completed THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS completion_pct,
9 ROUND(SUM(p.watch_seconds) / 3600.0, 0) AS total_watch_hours,
10 ROUND(SUM(p.watch_seconds) / 3600.0 / SUM(c.license_cost_eur) * 1000, 2) AS hours_per_1000eur,
11 -- Retención: % de usuarios del género que vuelven en 7 días
12 ROUND(
13 COUNT(DISTINCT CASE
14 WHEN EXISTS (
15 SELECT 1 FROM playbacks p2
16 WHERE p2.user_id = p.user_id
17 AND p2.content_id != p.content_id
18 AND DATE(p2.started_at) BETWEEN DATE(p.started_at) + 1
19 AND DATE(p.started_at) + 7
20 ) THEN p.user_id END
21 ) * 100.0 / NULLIF(COUNT(DISTINCT p.user_id), 0),
22 1) AS pct_return_7d
23FROM content c
24JOIN playbacks p ON c.content_id = p.content_id
25WHERE p.started_at >= CURRENT_DATE - INTERVAL '90 days'
26 AND p.watch_seconds > 30
27GROUP BY c.genre
28HAVING COUNT(p.playback_id) >= 100
29ORDER BY hours_per_1000eur DESC;

Análisis por género con ROI y retención. La respuesta que Sofía necesita para invertir 200K EUR.

Los resultados revelan algo que contradice la intuición de Sofía. Ella pensaba que los documentales de naturaleza eran los más populares. Y tiene razón en alcance (más viewers únicos). Pero los documentales de true crime tienen una tasa de finalización un 20% mayor y generan 3x más horas de watch time por euro invertido en licencia. Además, los usuarios que ven true crime tienen un 45% de probabilidad de volver en 7 días, vs. 30% para naturaleza.

### Análisis por duración -- ¿series cortas o películas largas?

1-- Rendimiento por franja de duración
2SELECT
3 CASE
4 WHEN c.duration_seconds < 1200 THEN '< 20 min (corto)'
5 WHEN c.duration_seconds < 2700 THEN '20-45 min (episodio)'
6 WHEN c.duration_seconds < 5400 THEN '45-90 min (medio)'
7 WHEN c.duration_seconds < 7200 THEN '90-120 min (película)'
8 ELSE '> 120 min (largo)'
9 END AS duration_bucket,
10 COUNT(DISTINCT c.content_id) AS titles,
11 COUNT(DISTINCT p.user_id) AS unique_viewers,
12 ROUND(AVG(p.watch_seconds * 1.0 / c.duration_seconds) * 100, 1) AS avg_completion_pct,
13 ROUND(AVG(p.watch_seconds) / 60.0, 1) AS avg_watch_min,
14 ROUND(SUM(p.watch_seconds) / 3600.0, 0) AS total_hours,
15 -- Engagement: ¿está duración genera más sesiones por usuario?
16 ROUND(COUNT(p.playback_id) * 1.0 / COUNT(DISTINCT p.user_id), 1) AS plays_per_viewer
17FROM content c
18JOIN playbacks p ON c.content_id = p.content_id
19WHERE p.started_at >= CURRENT_DATE - INTERVAL '90 days'
20 AND p.watch_seconds > 30
21GROUP BY duration_bucket
22ORDER BY avg_completion_pct DESC;

Análisis por duración: los episodios de 20-45 min tienen el completion rate más alto.

El hallazgo clave para Sofía: los contenidos de 20-45 minutos (formato episodio) tienen un completion rate del 68%, vs. 38% para películas de 90+ minutos. Además generan más sesiones por viewer (2.4 vs 1.1) porque la gente vuelve a ver el siguiente episodio. Series cortas de 6-8 episodios son el formato ideal para StreamVibe. La recomendación: invertir el 60% del presupuesto Q2 en series de episodios cortos.

### La presentación a Sofía -- datos que toman decisiones

A las 17:00 te sientas con Sofía 15 minutos y le muestras los resultados. No le enseñas las queries SQL -- le enseñas 3 gráficos simples y una recomendación clara:

La clave de comunicar datos a stakeholders no técnicos (lección de AdPulse): no muestres el proceso, muestra el resultado. Sofía no necesita saber que hiciste un JOIN de 3 tablas con window functions. Necesita saber: "invierte en true crime porque retiene 3x más y cuesta la mitad que naturaleza". Punto.

  1. 01.Géneros: true crime y documentales sociales generan 3x más retención que naturaleza. Recomendación: priorizar true crime y social para Q2.
  2. 02.Duración: episodios de 20-45 min tienen 68% completion vs 38% en películas. Recomendación: series cortas (6-8 episodios) son el formato ganador.
  3. 03.ROI: las series documentales de 6 episodios generan 4.2 horas de watch time por euro invertido en licencia, vs 1.1 hora por euro de películas.
  4. 04.Propuesta de inversión Q2: 120K EUR en series documentales cortas (true crime + social), 50K EUR en cine europeo (prestigio + retention de power users), 30K EUR en cortometrajes (reach + onboarding de nuevos usuarios).

Sofía está encantada: "Es la primera vez en 18 meses que alguien me da datos reales para tomar está decisión. Antes era yo sola con mi intuición y los 4 emails de feedback que recibimos al mes. Con esto puedo defender mi presupuesto ante Marta con números." Le prometes que la semana que viene tendrá un dashboard actualizado semanalmente con el performance de cada título.

Lo que acabas de hacer con Sofía es lo que diferencia a un data engineer senior de uno mid: no solo calculaste métricas -- las tradujiste en una DECISIÓN de negocio concreta. "Invierte 120K en series documentales de true crime" es infinitamente más útil que "aquí tienes un dashboard con 15 gráficos". El senior entrega decisiones, no datos.

### El modelo dimensional de contenido

Para que el análisis de contenido sea sostenible (no solo un one-off de está tarde), diseñas un modelo dimensional simple en la zona gold del lake que Metabase pueda consultar directamente:

1-- Tabla gold: content_performance (se actualiza cada noche)
2CREATE TABLE gold_content_performance AS
3SELECT
4 c.content_id,
5 c.title,
6 c.content_type,
7 c.genre,
8 c.duration_seconds / 60 AS duration_minutes,
9 c.release_year,
10 c.rating_imdb,
11 c.license_cost_eur,
12 c.is_premium,
13 -- Métricas de performance (últimos 90 días)
14 COUNT(p.playback_id) AS total_plays_90d,
15 COUNT(DISTINCT p.user_id) AS unique_viewers_90d,
16 SUM(p.watch_seconds) / 3600.0 AS total_hours_90d,
17 AVG(p.watch_seconds) / 60.0 AS avg_watch_minutes,
18 SUM(CASE WHEN p.completed THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS completion_pct,
19 -- ROI
20 CASE WHEN c.license_cost_eur > 0
21 THEN SUM(p.watch_seconds) / 3600.0 / c.license_cost_eur * 1000
22 ELSE 0 END AS hours_per_1000eur,
23 -- Timestamp de actualización
24 CURRENT_TIMESTAMP AS updated_at
25FROM content c
26LEFT JOIN playbacks p ON c.content_id = p.content_id
27 AND p.started_at >= CURRENT_DATE - INTERVAL '90 days'
28 AND p.watch_seconds > 30
29GROUP BY c.content_id, c.title, c.content_type, c.genre,
30 c.duration_seconds, c.release_year, c.rating_imdb,
31 c.license_cost_eur, c.is_premium;

Tabla gold de content performance: se actualiza cada noche, Sofía la consulta cuando quiera.

### Resumen del Día 3 (tarde)

  • Diseñaste Content Performance Score: alcance (30%) + finalización (40%) + ROI (30%)
  • Analizaste rendimiento por género: true crime > naturaleza en retención y ROI
  • Analizaste rendimiento por duración: episodios 20-45 min son el formato ganador
  • Entregaste recomendación concreta a Sofía para inversión de 200K EUR en Q2
  • Sofía tiene datos para defender su presupuesto por primera vez en 18 meses

## ejercicios

[01]

Content Performance Score completo

Implementa en Python el cálculo del Content Performance Score que combina alcance, finalización y ROI. Genera un ranking de los top 20 títulos y un resumen por género para Sofía.

Cargando editor...
[02]

ROI por género para decisiones de licencia

Sofía tiene 200K EUR de presupuesto. Implementa una función Python que, dado el análisis de rendimiento por género, genere una propuesta de distribución del presupuesto optimizando para engagement y ROI.

Cargando editor...
[03]

Análisis de duración óptima

Sofía pregunta: "¿Series cortas o películas?" Implementa un análisis que compare franjas de duración por completion rate, engagement y retención. Genera la recomendación de formato.

Cargando editor...
[04]

Generar reporte de recomendación de inversión para Sofía

Genera el output final para Sofía: un reporte estructurado que combina el análisis de género y duración y produce una recomendación concreta de distribución de los 200K EUR del Q2.

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