Saltar a contenido

📊 Tarea 3: EDA Netflix con Visualizaciones - Fill in the Blanks

UT1: Análisis Exploratorio de Datos | Práctica Guiada

🎯 Objetivos Básicos

  • Aprender a cargar y explorar datasets reales
  • Crear visualizaciones efectivas con matplotlib y seaborn
  • Identificar patrones y tendencias en los datos
  • Interpretar gráficos de forma correcta

📋 Lo que necesitas saber ANTES de empezar

  • Conceptos básicos de Python y pandas
  • Idea general de qué son las visualizaciones
  • Curiosidad por descubrir patrones en datos reales

🎬 Parte 1: Setup y Carga de Datos

📋 CONTEXTO DE NEGOCIO (CRISP-DM: Business Understanding)

🔗 Referencias oficiales:

🎬 Caso de negocio:

  • Problema: Netflix necesita entender mejor su catálogo para tomar decisiones estratégicas
  • Objetivo: Analizar patrones en el contenido, países de origen, y tendencias temporales
  • Variables: Tipo de contenido, país, fecha de lanzamiento, rating, géneros, etc.
  • Valor para el negocio: Optimizar la adquisición de contenido, entender audiencias globales
# Importar librerías que vamos a usar
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Configurar el estilo de visualizaciones
plt.style.use('_______')  # establecer estilo visual (ej: 'default', 'seaborn', 'classic')
sns.set_palette("_______")  # definir paleta de colores (ej: 'husl', 'Set1', 'viridis')
plt.rcParams['figure.figsize'] = (10, 6)  # tamaño por defecto

print("✅ Setup completo!")

💡 PISTAS:

🎬 Paso 2: Cargar y Explorar Dataset Netflix

# === CARGAR DATOS DE NETFLIX ===

# 1. Cargar el dataset desde una URL
url = "https://raw.githubusercontent.com/swapnilg4u/Netflix-Data-Analysis/refs/heads/master/netflix_titles.csv"
df = pd._______(url)  # función para leer archivos CSV desde URL o archivo local

print("🎬 DATASET: Netflix Titles")
print(f"   📊 Forma: {df.shape}")
print(f"   📋 Columnas: {list(df.columns)}")

# 2. Explorar los datos básicamente
print("\n🔍 Primeras 5 filas:")
print(df._____())  # método para mostrar las primeras filas del DataFrame

# 3. Información sobre tipos de datos y memoria
print("\n📋 INFORMACIÓN GENERAL:")
print(df._____())  # método que muestra tipos de datos, memoria y valores no nulos

# 4. Estadísticas básicas para columnas numéricas
print("\n📊 ESTADÍSTICAS BÁSICAS:")
print(df._____())  # método que calcula estadísticas descriptivas (mean, std, min, max, etc.)

💡 PISTAS:

  • 📚 ¿Qué método de pandas se usa para leer archivos CSV? Documentación
  • 👀 ¿Cuál método muestra las primeras filas? Documentación
  • ℹ️ ¿Cuál método da información sobre tipos y memoria? Documentación
  • 📊 ¿Cuál método calcula estadísticas descriptivas? Documentación

📊 Paso 3: Análisis de Datos Faltantes

# === DETECTAR Y VISUALIZAR DATOS FALTANTES ===

# 1. Calcular datos faltantes por columna
missing_data = df.______().sum().sort_values(ascending=False)  # detectar valores nulos y contar por columna
missing_percent = (df.______().sum() / len(df) * 100).sort_values(ascending=False)  # calcular porcentaje de nulos

print("❌ DATOS FALTANTES:")
print(missing_data[missing_data > 0])
print("\n📊 PORCENTAJES:")
print(missing_percent[missing_percent > 0])

# 2. Crear visualización de datos faltantes
plt.figure(figsize=(12, 6))

# Subplot 1: Gráfico de barras de datos faltantes
plt.subplot(1, 2, 1)
sns._______(x=missing_percent[missing_percent > 0].values,  # función para crear barras horizontales
            y=missing_percent[missing_percent > 0].index,
            palette='Reds_r')
plt.title('Porcentaje de Datos Faltantes por Columna')
plt.xlabel('Porcentaje (%)')

# Subplot 2: Heatmap de datos faltantes
plt.subplot(1, 2, 2)
sns._______(df.isnull(), cbar=True, cmap='viridis')  # función para crear mapa de calor de valores booleanos
plt.title('Patrón de Datos Faltantes')
plt.xticks(rotation=45)

plt.tight_layout()
plt._____()  # función para mostrar/renderizar los gráficos en pantalla

💡 PISTAS:

🔍 Paso 4: Detección de Valores Atípicos y Anomalías

# === DETECCIÓN DE OUTLIERS Y ANOMALÍAS ===

# 1. Analizar años de lanzamiento atípicos
print("🔍 ANÁLISIS DE OUTLIERS EN AÑOS:")
df['release_year_clean'] = pd.to_numeric(df['release_year'], errors='coerce')
year_stats = df['release_year_clean'].describe()
print(year_stats)

# Identificar años sospechosos
very_old = df[df['release_year_clean'] < 1950]
future_releases = df[df['release_year_clean'] > 2025]

print(f"\n⚠️ Contenido muy antiguo (< 1950): {len(very_old)} títulos")
if len(very_old) > 0:
    print("Ejemplos:")
    print(very_old[['title', 'release_year', 'type']].head())

print(f"\n⚠️ Lanzamientos futuros (> 2025): {len(future_releases)} títulos")
if len(future_releases) > 0:
    print("Ejemplos:")
    print(future_releases[['title', 'release_year', 'type']].head())

# 2. Crear visualizaciones para detectar outliers
fig, axes = plt.subplots(2, 2, figsize=(15, 10))

# Gráfico 1: Box plot para detectar outliers en años
sns._______(data=df, y='release_year_clean', ax=axes[0, 0])  # función para mostrar outliers con cajas
axes[0, 0].set_title('Box Plot - Años de Lanzamiento (Outliers)')
axes[0, 0].set_ylabel('Año de Lanzamiento')

# Gráfico 2: Histograma de años para ver distribución
axes[0, 1]._______(df['release_year_clean'].dropna(), bins=50, alpha=0.7, color='skyblue', edgecolor='black')  # histograma con muchos bins
axes[0, 1].set_title('Distribución de Años de Lanzamiento')
axes[0, 1].set_xlabel('Año')
axes[0, 1].set_ylabel('Frecuencia')
axes[0, 1].axvline(df['release_year_clean'].mean(), color='red', linestyle='--', label='Media')
axes[0, 1].legend()

# Gráfico 3: Análisis de títulos duplicados
title_counts = df['title']._______()  # contar frecuencias de títulos
duplicated_titles = title_counts[title_counts > 1]

print(f"\n🔄 TÍTULOS DUPLICADOS: {len(duplicated_titles)} títulos aparecen múltiples veces")
if len(duplicated_titles) > 0:
    top_duplicates = duplicated_titles.head(10)
    sns._______(y=top_duplicates.index, x=top_duplicates.values, ax=axes[1, 0], palette='Reds')  # barras horizontales
    axes[1, 0].set_title('Top 10 Títulos Duplicados')
    axes[1, 0].set_xlabel('Cantidad de Apariciones')
else:
    axes[1, 0].text(0.5, 0.5, 'No se encontraron\ntítulos duplicados', 
                    ha='center', va='center', transform=axes[1, 0].transAxes)
    axes[1, 0].set_title('Títulos Duplicados - Sin Datos')

# Gráfico 4: Longitud de títulos (outliers en texto)
df['title_length'] = df['title'].str.len()
title_length_stats = df['title_length'].describe()

sns._______(data=df, y='title_length', ax=axes[1, 1])  # box plot para longitud de títulos
axes[1, 1].set_title('Box Plot - Longitud de Títulos')
axes[1, 1].set_ylabel('Caracteres en el Título')

# Identificar títulos extremadamente largos o cortos
very_long_titles = df[df['title_length'] > df['title_length'].quantile(0.99)]
very_short_titles = df[df['title_length'] < 5]

print(f"\n📏 TÍTULOS EXTREMOS:")
print(f"   Muy largos (> percentil 99): {len(very_long_titles)} títulos")
if len(very_long_titles) > 0:
    print(f"   Ejemplo más largo: '{very_long_titles.loc[very_long_titles['title_length'].idxmax(), 'title']}'")

print(f"   Muy cortos (< 5 caracteres): {len(very_short_titles)} títulos")
if len(very_short_titles) > 0:
    print("   Ejemplos:")
    print(very_short_titles[['title', 'title_length', 'type']].head())

plt.tight_layout()
plt.show()

print("✅ Análisis de outliers completado!")

💡 PISTAS:


🎭 Paso 5: Análisis de Tipos de Contenido

# === ANÁLISIS DE TIPOS DE CONTENIDO ===

# 1. Calcular frecuencias
type_counts = df['type']._______()  # método para contar frecuencias de cada categoría única
type_percent = df['type']._______(normalize=True) * 100  # mismo método pero calculando porcentajes

print("🎭 TIPOS DE CONTENIDO:")
print(type_counts)
print(f"\nPorcentajes:")
print(type_percent)

# 2. Crear visualizaciones múltiples
fig, axes = plt.subplots(2, 2, figsize=(15, 10))

# Gráfico 1: Countplot básico
sns._______(data=df, x='type', ax=axes[0, 0], palette='Set2')  # función para contar y graficar categorías
axes[0, 0].set_title('Distribución: Movies vs TV Shows')
axes[0, 0].set_ylabel('Cantidad')

# Gráfico 2: Pie chart
axes[0, 1]._______(type_counts.values, labels=type_counts.index,  # función para crear gráfico circular/torta
                  autopct='%1.1f%%', startangle=90, colors=['skyblue', 'lightcoral'])
axes[0, 1].set_title('Proporción Movies vs TV Shows')

# Gráfico 3: Barplot horizontal
sns._______(y=type_counts.index, x=type_counts.values, ax=axes[1, 0], palette='viridis')  # función para barras horizontales
axes[1, 0].set_title('Cantidad por Tipo (Horizontal)')
axes[1, 0].set_xlabel('Cantidad')

# Gráfico 4: Donut chart (más avanzado)
wedges, texts, autotexts = axes[1, 1]._______(type_counts.values, labels=type_counts.index,  # misma función de torta para donut
                                             autopct='%1.1f%%', startangle=90,
                                             colors=['gold', 'lightgreen'])
# Crear el hueco del donut
centre_circle = plt.Circle((0,0), 0.70, fc='white')
axes[1, 1].add_artist(centre_circle)
axes[1, 1].set_title('Donut Chart - Tipos de Contenido')

plt.tight_layout()
plt.show()

💡 PISTAS:

📅 Paso 6: Análisis Temporal

# === ANÁLISIS DE TENDENCIAS TEMPORALES ===

# 1. Preparar datos temporales
df['release_year'] = pd._______(df['release_year'], errors='coerce')  # convertir a numérico, NaN si no es posible
yearly_releases = df['release_year']._______().sort_index()  # contar frecuencias por año y ordenar

# Filtrar años recientes para mejor visualización
recent_years = yearly_releases[yearly_releases.index >= 2000]

# 2. Crear visualizaciones temporales múltiples
fig, axes = plt.subplots(2, 2, figsize=(16, 12))

# Gráfico 1: Línea temporal
axes[0, 0]._______(recent_years.index, recent_years.values,  # función para crear líneas conectando puntos
                  marker='o', linewidth=2, markersize=4, color='darkblue')
axes[0, 0].set_title('Cantidad de Contenido por Año (2000-2021)')
axes[0, 0].set_xlabel('Año')
axes[0, 0].set_ylabel('Cantidad de Títulos')
axes[0, 0].grid(True, alpha=0.3)

# Gráfico 2: Área bajo la curva
axes[0, 1]._______(recent_years.index, recent_years.values,  # función para rellenar área bajo la línea
                  alpha=0.7, color='lightcoral')
axes[0, 1].set_title('Área - Lanzamientos por Año')
axes[0, 1].set_xlabel('Año')
axes[0, 1].set_ylabel('Cantidad')

# Gráfico 3: Análisis por tipo de contenido
df_recent = df[df['release_year'] >= 2010]
yearly_by_type = df_recent.groupby(['release_year', 'type']).size().unstack(fill_value=0)

yearly_by_type.plot(kind='_______', ax=axes[1, 0],  # tipo de gráfico con barras lado a lado (no apiladas)
                    color=['skyblue', 'lightgreen'], alpha=0.8)
axes[1, 0].set_title('Lanzamientos por Tipo (2010-2021)')
axes[1, 0].set_xlabel('Año')
axes[1, 0].set_ylabel('Cantidad')
axes[1, 0].legend(title='Tipo')

# Gráfico 4: Heatmap de lanzamientos por década y tipo
df['decade'] = (df['release_year'] // 10) * 10
decade_type = df.groupby(['decade', 'type']).size().unstack(fill_value=0)
sns._______(decade_type, annot=True, fmt='d', ax=axes[1, 1], cmap='YlOrRd')  # función para mapa de calor con anotaciones
axes[1, 1].set_title('Heatmap: Lanzamientos por Década y Tipo')

plt.tight_layout()
plt.show()

print("📅 AÑOS CON MÁS LANZAMIENTOS:")
print(yearly_releases.tail(10))

💡 PISTAS:

  • 🔢 ¿Qué función convierte a numérico? Documentación
  • 📈 ¿Qué método de matplotlib crea líneas? Documentación
  • 🌊 ¿Qué método crea gráficos de área? Documentación
  • 📊 ¿Qué tipo de gráfico muestra barras superpuestas? ('bar', 'line', 'area')
  • 🔥 Ya sabes qué función crea heatmaps de seaborn...

🌍 Paso 7: Análisis Geográfico

# === ANÁLISIS DE PAÍSES CON VISUALIZACIONES ===

# 1. Preparar datos de países (limpiar y separar países múltiples)
df_countries = df.dropna(subset=['country']).copy()

# Separar países que están separados por comas
countries_expanded = df_countries['country'].str.split(', ').explode()
country_counts = countries_expanded._______().head(20)  # contar frecuencias de países y tomar top 20

print("🌍 TOP 20 PAÍSES CON MÁS CONTENIDO:")
print(country_counts)

# 2. Crear visualizaciones geográficas
fig, axes = plt.subplots(2, 2, figsize=(18, 12))

# Gráfico 1: Top 15 países - barras horizontales
top_15_countries = country_counts.head(15)
sns._______(y=top_15_countries.index, x=top_15_countries.values,  # función para barras horizontales
           ax=axes[0, 0], palette='viridis')
axes[0, 0].set_title('Top 15 Países con Más Contenido')
axes[0, 0].set_xlabel('Cantidad de Títulos')

# Gráfico 2: Treemap simulado con scatter
top_10 = country_counts.head(10)
colors = plt.cm.Set3(np.linspace(0, 1, len(top_10)))
axes[0, 1]._______(range(len(top_10)), top_10.values,  # función para gráfico de burbujas/puntos
                  s=top_10.values*3, c=colors, alpha=0.7)
for i, (country, count) in enumerate(top_10.items()):
    axes[0, 1].annotate(f'{country}\n({count})', 
                       (i, count), ha='center', va='center')
axes[0, 1].set_title('Bubble Chart - Top 10 Países')
axes[0, 1].set_xticks(range(len(top_10)))
axes[0, 1].set_xticklabels(top_10.index, rotation=45)

# Gráfico 3: Análisis de contenido por país y tipo
top_countries = country_counts.head(10).index
df_top_countries = df_countries[df_countries['country'].isin(top_countries)]
country_type = df_top_countries.groupby(['country', 'type']).size().unstack(fill_value=0)

country_type.plot(kind='_______', ax=axes[1, 0],  # tipo de gráfico con barras agrupadas lado a lado
                  color=['lightblue', 'salmon'], width=0.8)
axes[1, 0].set_title('Movies vs TV Shows por País (Top 10)')
axes[1, 0].set_ylabel('Cantidad')
axes[1, 0].legend(title='Tipo')
axes[1, 0].tick_params(axis='x', rotation=45)

# Gráfico 4: Heatmap de correlación entre países principales
# Crear matriz de co-ocurrencia de países
from itertools import combinations
co_occurrence = {}
for countries_str in df_countries['country']:
    if pd.notna(countries_str) and ',' in countries_str:
        countries_list = [c.strip() for c in countries_str.split(',')]
        for c1, c2 in combinations(countries_list, 2):
            if c1 in top_10.index and c2 in top_10.index:
                key = tuple(sorted([c1, c2]))
                co_occurrence[key] = co_occurrence.get(key, 0) + 1

# Crear matriz para heatmap
co_matrix = np.zeros((len(top_10), len(top_10)))
for i, c1 in enumerate(top_10.index):
    for j, c2 in enumerate(top_10.index):
        if i != j:
            key = tuple(sorted([c1, c2]))
            co_matrix[i, j] = co_occurrence.get(key, 0)

sns._______(co_matrix, annot=True, fmt='.0f',  # función para mapa de calor (formato .0f para números flotantes)
           xticklabels=top_10.index, yticklabels=top_10.index,
           ax=axes[1, 1], cmap='Reds')
axes[1, 1].set_title('Co-producción entre Países')
axes[1, 1].tick_params(axis='x', rotation=45)
axes[1, 1].tick_params(axis='y', rotation=0)

plt.tight_layout()
plt.show()

💡 PISTAS:

  • 📊 Ya conoces barplot para barras horizontales...
  • 🫧 ¿Qué función crea gráficos de burbujas? Documentación
  • 📊 ¿Qué tipo de gráfico muestra barras una al lado de la otra? (hint: no es 'stacked')
  • 🔥 ¿Ya olvidaste cómo hacer heatmaps? 😉

🎨 Paso 8: Análisis de Géneros y Ratings

# === ANÁLISIS DE RATINGS Y GÉNEROS ===

# 1. Preparar datos de ratings
rating_counts = df['rating']._______().head(10)  # contar frecuencias de ratings y tomar top 10

print("🔞 TOP 10 RATINGS MÁS COMUNES:")
print(rating_counts)

# 2. Crear dashboard de ratings
fig, axes = plt.subplots(2, 3, figsize=(20, 12))

# Gráfico 1: Countplot de ratings
sns._______(data=df, x='rating', order=rating_counts.index,  # función para contar y graficar categorías ordenadas
           ax=axes[0, 0], palette='Set1')
axes[0, 0].set_title('Distribución de Ratings')
axes[0, 0].tick_params(axis='x', rotation=45)

# Gráfico 2: Ratings por tipo de contenido
sns._______(data=df, x='rating', hue='type',  # misma función pero separando por otra variable (hue)
           order=rating_counts.index, ax=axes[0, 1])
axes[0, 1].set_title('Ratings por Tipo de Contenido')
axes[0, 1].tick_params(axis='x', rotation=45)
axes[0, 1].legend(title='Tipo')

# Gráfico 3: Pie chart de ratings principales
top_5_ratings = rating_counts.head(5)
axes[0, 2]._______(top_5_ratings.values, labels=top_5_ratings.index,  # función para gráfico circular/torta
                  autopct='%1.1f%%', startangle=90)
axes[0, 2].set_title('Top 5 Ratings - Proporción')

# Gráfico 4: Box plot de años de lanzamiento por rating
df_clean = df.dropna(subset=['rating', 'release_year'])
top_ratings = rating_counts.head(6).index
df_top_ratings = df_clean[df_clean['rating'].isin(top_ratings)]

sns._______(data=df_top_ratings, x='rating', y='release_year',  # función para mostrar distribución con cajas y bigotes
           order=top_ratings, ax=axes[1, 0])
axes[1, 0].set_title('Distribución de Años por Rating')
axes[1, 0].tick_params(axis='x', rotation=45)

# Gráfico 5: Violin plot alternativo
sns._______(data=df_top_ratings, x='rating', y='release_year',  # función para mostrar densidad como "violines"
           order=top_ratings, ax=axes[1, 1], palette='muted')
axes[1, 1].set_title('Densidad de Años por Rating')
axes[1, 1].tick_params(axis='x', rotation=45)

# Gráfico 6: Heatmap de rating vs década
df_clean['decade'] = (df_clean['release_year'] // 10) * 10
rating_decade = df_clean.groupby(['rating', 'decade']).size().unstack(fill_value=0)
# Filtrar solo ratings principales y décadas recientes
rating_decade_filtered = rating_decade.loc[top_ratings, rating_decade.columns >= 1980]

sns._______(rating_decade_filtered, annot=True, fmt='d',  # función para mapa de calor con valores enteros
           ax=axes[1, 2], cmap='Blues')
axes[1, 2].set_title('Heatmap: Rating vs Década')
axes[1, 2].tick_params(axis='x', rotation=45)

plt.tight_layout()
plt.show()

💡 PISTAS:

  • 📊 Usas value_counts() para contar categorías
  • 📈 countplot ya lo usaste antes
  • 🎨 countplot con hue= separa por categorías Documentación
  • 🥧 pie ya lo usaste arriba
  • 📦 ¿Qué función crea box plots? Documentación
  • 🎻 ¿Qué función crea violin plots? Documentación
  • 🔥 heatmap... ya sabes 😉

📊 Paso 9: Dashboard Final

# === CREAR DASHBOARD FINAL INTERACTIVO ===

# 1. Calcular estadísticas finales
total_titles = len(df)
total_movies = len(df[df['type'] == 'Movie'])
total_shows = len(df[df['type'] == 'TV Show'])
latest_year = df['release_year'].max()
oldest_year = df['release_year'].min()

print(f"📊 RESUMEN EJECUTIVO NETFLIX:")
print(f"   Total de títulos: {total_titles:,}")
print(f"   Películas: {total_movies:,} ({total_movies/total_titles*100:.1f}%)")
print(f"   Series: {total_shows:,} ({total_shows/total_titles*100:.1f}%)")
print(f"   Rango de años: {oldest_year} - {latest_year}")

# 2. Crear figura principal con subplots
fig = plt.figure(figsize=(20, 15))
gs = fig.add_gridspec(3, 4, hspace=0.3, wspace=0.3)

# Dashboard panel 1: Tipos (grande)
ax1 = fig.add_subplot(gs[0, :2])
type_data = df['type'].value_counts()
colors = ['#FF6B6B', '#4ECDC4']
wedges, texts, autotexts = ax1._______(type_data.values, labels=type_data.index,  # función para gráfico de torta en dashboard
                                       autopct='%1.1f%%', startangle=90,
                                       colors=colors, textprops={'fontsize': 12})
ax1.set_title('Distribución Movies vs TV Shows', fontsize=14, fontweight='bold')

# Dashboard panel 2: Timeline
ax2 = fig.add_subplot(gs[0, 2:])
yearly = df.groupby('release_year').size()
recent_years = yearly[yearly.index >= 2000]
ax2._______(recent_years.index, recent_years.values, color='#FF6B6B', alpha=0.7)  # función para rellenar área bajo curva
ax2.plot(recent_years.index, recent_years.values, color='darkred', linewidth=2)
ax2.set_title('Evolución Temporal (2000+)', fontsize=14, fontweight='bold')
ax2.set_xlabel('Año')
ax2.set_ylabel('Títulos Lanzados')
ax2.grid(True, alpha=0.3)

# Dashboard panel 3: Top países
ax3 = fig.add_subplot(gs[1, :2])
country_clean = df.dropna(subset=['country'])['country'].str.split(', ').explode()
top_countries = country_clean.value_counts().head(10)
sns._______(y=top_countries.index, x=top_countries.values, ax=ax3, palette='viridis')  # función para barras horizontales
ax3.set_title('Top 10 Países Productores', fontsize=14, fontweight='bold')
ax3.set_xlabel('Cantidad de Títulos')

# Dashboard panel 4: Ratings
ax4 = fig.add_subplot(gs[1, 2:])
top_ratings = df['rating'].value_counts().head(8)
sns._______(data=df[df['rating'].isin(top_ratings.index)],  # función para contar categorías separadas por hue
           x='rating', hue='type', order=top_ratings.index, ax=ax4)
ax4.set_title('Ratings por Tipo de Contenido', fontsize=14, fontweight='bold')
ax4.tick_params(axis='x', rotation=45)
ax4.legend(title='Tipo')

# Dashboard panel 5: Heatmap temporal (full width)
ax5 = fig.add_subplot(gs[2, :])
df['decade'] = (df['release_year'] // 10) * 10
year_type_decade = df.groupby(['decade', 'type']).size().unstack(fill_value=0)
sns._______(year_type_decade.T, annot=True, fmt='d', ax=ax5,  # función para mapa de calor transpuesto (.T)
           cmap='YlOrRd', cbar_kws={'label': 'Cantidad de Títulos'})
ax5.set_title('Evolución por Décadas y Tipo de Contenido', fontsize=14, fontweight='bold')
ax5.set_xlabel('Década')
ax5.set_ylabel('Tipo de Contenido')

# Guardar el dashboard
plt.suptitle('📊 NETFLIX CONTENT ANALYSIS DASHBOARD', fontsize=18, fontweight='bold', y=0.95)
plt._______(f'netflix_dashboard.png', dpi=300, bbox_inches='tight')  # función para guardar figura como archivo
plt.show()

print("\n✅ Dashboard guardado como 'netflix_dashboard.png'")

💡 PISTAS:

  • 🥧 pie() ya lo conoces
  • 🌊 fill_between() para gráficos de área
  • 📊 barplot() horizontal con y= y x=
  • 📈 countplot() con hue=
  • 🔥 heatmap() con datos transpuestos (.T)
  • 💾 ¿Cómo guardar figuras? Documentación

📋 Paso 10: Análisis de Géneros y Duración

# === ANÁLISIS AVANZADO DE GÉNEROS ===

# 1. Separar géneros que están en lista separada por comas
genres_expanded = df.dropna(subset=['listed_in'])['listed_in'].str.split(', ').explode()
top_genres = genres_expanded._______().head(15)  # contar frecuencias de géneros y tomar top 15

print("🎬 TOP 15 GÉNEROS MÁS POPULARES:")
print(top_genres)

# 2. Crear visualización de géneros
fig, axes = plt.subplots(2, 2, figsize=(16, 10))

# Word cloud simulado con scatter
axes[0, 0]._______(range(len(top_genres)), top_genres.values,  # función para gráfico de burbujas (scatter)
                  s=top_genres.values*2, alpha=0.6, c=range(len(top_genres)), cmap='viridis')
for i, (genre, count) in enumerate(top_genres.items()):
    axes[0, 0].annotate(genre, (i, count), ha='center', va='center', fontsize=8)
axes[0, 0].set_title('Bubble Chart - Géneros Populares')
axes[0, 0].set_xticks([])

# Barras horizontales de géneros
sns._______(y=top_genres.head(10).index, x=top_genres.head(10).values,  # función para barras horizontales
           ax=axes[0, 1], palette='Set2')
axes[0, 1].set_title('Top 10 Géneros')
axes[0, 1].set_xlabel('Cantidad')

# Análisis de duración de películas
movies_df = df[df['type'] == 'Movie'].copy()
movies_df['duration_min'] = movies_df['duration'].str.extract('(\d+)').astype(float)

axes[1, 0]._______(movies_df['duration_min'], bins=30, alpha=0.7, color='lightcoral', edgecolor='black')  # función para histograma de frecuencias
axes[1, 0].set_title('Distribución Duración Películas')
axes[1, 0].set_xlabel('Duración (minutos)')
axes[1, 0].set_ylabel('Frecuencia')
axes[1, 0].axvline(movies_df['duration_min'].mean(), color='red', linestyle='--', 
                   label=f'Media: {movies_df["duration_min"].mean():.0f} min')
axes[1, 0].legend()

# Análisis de temporadas de series
tv_shows_df = df[df['type'] == 'TV Show'].copy()
tv_shows_df['seasons'] = tv_shows_df['duration'].str.extract('(\d+)').astype(float)

axes[1, 1]._______(tv_shows_df['seasons'], bins=range(1, 20), alpha=0.7, color='lightblue', edgecolor='black')  # función para histograma con bins personalizados
axes[1, 1].set_title('Distribución Temporadas TV Shows')
axes[1, 1].set_xlabel('Número de Temporadas')
axes[1, 1].set_ylabel('Frecuencia')
axes[1, 1].axvline(tv_shows_df['seasons'].mean(), color='blue', linestyle='--',
                   label=f'Media: {tv_shows_df["seasons"].mean():.1f} temporadas')
axes[1, 1].legend()

plt.tight_layout()
plt.show()

print(f"\n📊 ESTADÍSTICAS DE DURACIÓN:")
print(f"   Película promedio: {movies_df['duration_min'].mean():.0f} minutos")
print(f"   Película más corta: {movies_df['duration_min'].min():.0f} minutos")
print(f"   Película más larga: {movies_df['duration_min'].max():.0f} minutos")
print(f"   Serie promedio: {tv_shows_df['seasons'].mean():.1f} temporadas")
print(f"   Serie más larga: {tv_shows_df['seasons'].max():.0f} temporadas")

💡 PISTAS:

  • 📊 value_counts() para contar géneros
  • 🫧 scatter() para bubbles
  • 📊 barplot() horizontal
  • 📈 ¿Qué función crea histogramas? Documentación

🤔 Paso 11: Preguntas de Reflexión

Responde estas preguntas después de completar el código:

  1. ¿Qué tipo de visualización es más efectiva para mostrar distribuciones temporales? 💡 PISTA: Compara line plot vs area plot vs bar plot

  2. ¿Por qué usamos diferentes tipos de gráficos para diferentes datos? 💡 PISTA: 🔗 Guía de tipos de gráficos

  3. ¿Qué insights de negocio obtuviste que Netflix podría usar? 💡 PISTA: Piensa en estrategias de contenido, mercados objetivo, tipos de producción

  4. ¿Cuál fue la visualización más reveladora y por qué? 💡 PISTA: ¿Qué patrón no esperabas ver?

  5. ¿Cómo mejorarías este análisis con más datos? 💡 PISTA: Datos de audiencia, ratings de IMDb, presupuestos, etc.


🚀 BONUS: Profiling Automático con ydata-profiling

🤖 Paso 12: EDA Automático con ydata-profiling

# === PROFILING AUTOMÁTICO DEL DATASET ===

# 1. Instalar ydata-profiling (si no está instalado)
!pip install ydata-profiling

# 2. Importar y generar el reporte
from ydata_profiling import _______  # clase principal para generar reportes

print("🤖 Generando reporte automático de EDA...")

# 3. Crear perfil del dataset
profile = _______(df, title="Netflix Dataset - EDA Report", explorative=True)  # función principal para crear perfil

# 4. Personalizar el reporte
profile.config.html.minify_html = False  # HTML más legible
profile.config.html.use_local_assets = True  # usar assets locales

# 5. Generar reporte HTML
profile._______("netflix_eda_report.html")  # método para guardar reporte como HTML

profile

💡 PISTAS:

  • 📊 ¿Cuál es la clase principal de ydata-profiling? Documentación
  • 🔧 ¿Qué función crea el perfil? (misma clase que importaste)
  • 💾 ¿Qué método guarda el reporte? (hint: to_file)
  • 📋 ¿Qué método obtiene datos del reporte? (hint: get_description)
  • ⚠️ ¿Qué método obtiene las alertas? (hint: get_alerts)

🏆 ¡Felicitaciones!

Lo que has aprendido:

  • Seguir un flujo lógico de EDA (carga → calidad → exploración → insights)
  • Cargar y explorar datasets reales con pandas
  • Detectar y visualizar datos faltantes y outliers
  • Crear múltiples tipos de visualizaciones con matplotlib y seaborn
  • Identificar patrones temporales, geográficos y categóricos
  • Construir dashboards informativos
  • Usar herramientas de profiling automático
  • Comparar análisis manual vs automático

🚀 Próximos pasos:

📊 Practica con otros datasets:

🎨 Herramientas avanzadas:

  • 📊 Plotly - Visualizaciones interactivas
  • 🗺️ Folium - Mapas interactivos
  • 📈 Altair - Grammar of graphics
  • 🤖 Sweetviz - Comparación automática de datasets