PyDA Course
📖 Lección 3 Avanzado ⏱ 25 minutos ⚡ +100 XP ColabKagglenbviewerBinderDeepnoteGitHub univariate · matplotlib · seaborn · distributions · histograms

Análisis Univariado Numérico

Analiza distribuciones, tendencia central, dispersión y forma de variables numéricas usando histogramas, gráficos KDE y diagramas de caja.

🎯 Lo que aprenderás:
  • Calcular e interpretar media, mediana, moda, desviación estándar, asimetría y curtosis para columnas numéricas
  • Crear histogramas, gráficos KDE, diagramas de caja y de violín con matplotlib y seaborn
  • Leer las formas de distribución para identificar asimetría, modalidad y valores atípicos
  • Elegir el tipo de gráfico adecuado según las características de los datos y los objetivos del análisis

El análisis univariado numérico examina una variable numérica a la vez. El objetivo es entender su distribución: dónde se agrupan los valores, cuán dispersos están, si la distribución es simétrica o asimétrica y si existen valores atípicos. Esta lección cubre los tipos de gráficos y los estadísticos de resumen fundamentales para los datos numéricos.

Conceptos clave

Estadísticos de resumen

Antes de graficar, calcula los números que describen la distribución:

python
import pandas as pd
import numpy as np

# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")

scores = df["math score"]

# Central tendency
print(f"Mean:   {scores.mean():.2f}")
print(f"Median: {scores.median():.2f}")

# Spread
print(f"Std:    {scores.std():.2f}")
print(f"IQR:    {scores.quantile(0.75) - scores.quantile(0.25):.2f}")
print(f"Range:  {scores.max() - scores.min()}")

# Shape
print(f"Skewness:  {scores.skew():.2f}")
print(f"Kurtosis:  {scores.kurtosis():.2f}")

Interpretación:

  • Asimetría > 0: cola sesgada a la derecha (p. ej., la mayoría de los puntajes bajos, unos pocos muy altos)
  • Asimetría < 0: cola sesgada a la izquierda (p. ej., la mayoría de los puntajes altos, unos pocos muy bajos)
  • Curtosis > 0: colas pesadas (más valores atípicos que lo normal)
  • Curtosis < 0: colas ligeras (menos valores atípicos que lo normal)

Histogramas

El histograma es la base del análisis univariado numérico. Muestra la distribución de frecuencias:

python
import matplotlib.pyplot as plt
import seaborn as sns

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Basic histogram
axes[0].hist(scores, bins=20, edgecolor="black", alpha=0.7)
axes[0].set_title("Math Score Distribution (histogram)")
axes[0].set_xlabel("Math Score")
axes[0].set_ylabel("Frequency")

# Histogram with KDE overlay
sns.histplot(scores, kde=True, bins=20, ax=axes[1], color="steelblue")
axes[1].set_title("Math Score Distribution (histogram + KDE)")

plt.tight_layout()
plt.show()

Decisiones clave:

  • Número de intervalos (bins): demasiado pocos ocultan detalles, demasiados crean ruido. bins=20 es un valor predeterminado razonable para conjuntos de datos de menos de 10 000 filas. Usa bins="auto" para una selección automática.
  • Color del borde: edgecolor="black" hace visibles los límites de los intervalos.

Gráficos KDE (estimación de densidad por kernel)

Los gráficos KDE suavizan el histograma en una curva continua, lo que facilita comparar distribuciones e identificar la modalidad:

python
fig, ax = plt.subplots(figsize=(8, 5))

# Single KDE
sns.kdeplot(scores, fill=True, alpha=0.5, ax=ax)
ax.set_title("Math Score KDE")
ax.set_xlabel("Math Score")
plt.show()

# Compare distributions
fig, ax = plt.subplots(figsize=(8, 5))
for subject in ["math score", "reading score", "writing score"]:
    sns.kdeplot(df[subject], fill=True, alpha=0.3, label=subject, ax=ax)
ax.set_title("Score Distributions by Subject")
ax.legend()
plt.show()

Diagramas de caja

Los diagramas de caja muestran el resumen de cinco números (mínimo, Q1, mediana, Q3, máximo) y resaltan los valores atípicos:

python
fig, ax = plt.subplots(figsize=(8, 5))

sns.boxplot(x=scores, ax=ax, color="lightblue", flierprops=dict(marker="o", markersize=5))
ax.set_title("Math Score Box Plot")
ax.set_xlabel("Math Score")
plt.show()

Cómo leer un diagrama de caja:

  • Caja: rango intercuartílico (IQR), el 50% central de los datos
  • Línea dentro de la caja: mediana
  • Bigotes: 1.5 × IQR desde Q1 y Q3
  • Puntos más allá de los bigotes: valores atípicos (típicamente > 1.5 × IQR)

Diagramas de violín

Los diagramas de violín combinan el diagrama de caja con el KDE, mostrando tanto los estadísticos de resumen como la forma completa de la distribución:

python
fig, ax = plt.subplots(figsize=(8, 5))

sns.violinplot(x=scores, ax=ax, inner="quartile", color="lightgreen")
ax.set_title("Math Score Violin Plot")
ax.set_xlabel("Math Score")
plt.show()

El parámetro inner controla lo que se dibuja dentro del violín:

  • "quartile": muestra las líneas de Q1, la mediana y Q3
  • "box": muestra un diagrama de caja en miniatura
  • "stick": muestra todos los puntos de datos como marcas

Cómo elegir el gráfico adecuado

GráficoIdeal paraMuestra
HistogramaDistribución de frecuencias, formaIntervalos y conteos
KDEDistribución suave, comparar gruposCurva de densidad continua
Diagrama de cajaEstadísticos de resumen, valores atípicosResumen de cinco números
Diagrama de violínDistribución completa + resumenKDE + diagrama de caja combinados

Comparar distribuciones entre grupos

python
fig, axes = plt.subplots(1, 3, figsize=(15, 5), sharey=True)

for i, subject in enumerate(["math score", "reading score", "writing score"]):
    sns.boxplot(data=df, x="gender", y=subject, ax=axes[i])
    axes[i].set_title(subject.replace(" score", " Scores").title())

plt.tight_layout()
plt.show()

Inténtalo

Analiza la distribución del puntaje de lectura del conjunto de datos Students Performance.

python
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")

reading = df["reading score"]

# Summary statistics
print("Summary Statistics:")
print(f"  Mean:   {reading.mean():.2f}")
print(f"  Median: {reading.median():.2f}")
print(f"  Std:    {reading.std():.2f}")
print(f"  Skew:   {reading.skew():.2f}")

# Distribution plots
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

sns.histplot(reading, kde=True, bins=20, ax=axes[0], color="steelblue")
axes[0].set_title("Histogram + KDE")

sns.kdeplot(reading, fill=True, ax=axes[1], color="coral")
axes[1].set_title("KDE Only")

sns.boxplot(x=reading, ax=axes[2], color="lightgreen")
axes[2].set_title("Box Plot")

plt.tight_layout()
plt.show()

Conclusiones clave

  • Siempre calcula los estadísticos de resumen antes de graficar, te dicen qué buscar en la visualización
  • Los histogramas muestran frecuencias; los gráficos KDE muestran densidad; los diagramas de caja muestran estadísticos de resumen; los diagramas de violín combinan ambos
  • La asimetría y la curtosis cuantifican la forma de la distribución en números
  • Los diagramas de caja hacen obvios los valores atípicos; los histogramas revelan la modalidad (unimodal vs bimodal)
  • Compara distribuciones entre grupos graficándolas lado a lado con ejes compartidos

Desafío de práctica

Crea una sola figura con cuatro subgráficos que muestren la distribución de math score usando: (1) un histograma, (2) un gráfico KDE, (3) un diagrama de caja y (4) un diagrama de violín. Añade una línea vertical en la media en cada gráfico. Establece el título de la figura como “Math Score Distribution Analysis”.

🧩 Desafío, piensa primero, luego revela
python
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")

math = df["math score"]
mean_val = math.mean()

fig, axes = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle("Math Score Distribution Analysis", fontsize=14, fontweight="bold")

# Histogram
sns.histplot(math, kde=False, bins=20, ax=axes[0, 0], color="steelblue", edgecolor="black")
axes[0, 0].axvline(mean_val, color="red", linestyle="--", label=f"Mean: {mean_val:.1f}")
axes[0, 0].set_title("Histogram")
axes[0, 0].legend()

# KDE
sns.kdeplot(math, fill=True, ax=axes[0, 1], color="coral")
axes[0, 1].axvline(mean_val, color="red", linestyle="--", label=f"Mean: {mean_val:.1f}")
axes[0, 1].set_title("KDE Plot")
axes[0, 1].legend()

# Box plot
sns.boxplot(x=math, ax=axes[1, 0], color="lightgreen", flierprops=dict(marker="o", markersize=5))
axes[1, 0].axvline(mean_val, color="red", linestyle="--", label=f"Mean: {mean_val:.1f}")
axes[1, 0].set_title("Box Plot")
axes[1, 0].legend()

# Violin
sns.violinplot(x=math, ax=axes[1, 1], inner="quartile", color="lightyellow")
axes[1, 1].axvline(mean_val, color="red", linestyle="--", label=f"Mean: {mean_val:.1f}")
axes[1, 1].set_title("Violin Plot")
axes[1, 1].legend()

plt.tight_layout()
plt.show()
✅ Comprobación rápida +5 XP por pregunta

1. ¿Qué te dice describe() sobre una columna numérica?

2. ¿Cuándo deberías usar un histograma en lugar de un diagrama de caja?

3. ¿Qué indica una distribución asimétrica?

univariatematplotlibseaborndistributionshistograms