Long-form vs Wide-form: el formato que espera Seaborn
Una de las claves para usar Seaborn con eficacia es entender qué formato de datos esperan sus funciones. Seaborn trabaja preferentemente con datos en formato long-form (también llamado tidy data o datos ordenados), aunque muchas funciones también aceptan datos en formato wide-form.
Long-form (una observación por fila, una variable por columna):
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Ejemplo de datos long-form
datos_long = pd.DataFrame({
"persona": ["Ana", "Ana", "Ana", "Luis", "Luis", "Luis"],
"mes": ["Enero", "Febrero", "Marzo", "Enero", "Febrero", "Marzo"],
"ventas": [150, 180, 200, 120, 160, 190]
})
print(datos_long)
Salida:
persona mes ventas
0 Ana Enero 150
1 Ana Febrero 180
2 Ana Marzo 200
3 Luis Enero 120
4 Luis Febrero 160
5 Luis Marzo 190
Wide-form (cada variable en una columna separada):
# Ejemplo de datos wide-form
datos_wide = pd.DataFrame({
"mes": ["Enero", "Febrero", "Marzo"],
"Ana": [150, 180, 200],
"Luis": [120, 160, 190]
})
print(datos_wide)
Salida:
mes Ana Luis
0 Enero 150 120
1 Febrero 180 160
2 Marzo 200 190
Seaborn puede visualizar ambos formatos, pero la codificación visual (hue, size, style) es mucho más natural con long-form:
# Con long-form: el parámetro hue asigna color por persona automáticamente
sns.lineplot(data=datos_long, x="mes", y="ventas", hue="persona", marker="o")
plt.title("Ventas mensuales por persona (long-form)")
plt.show()
# Con wide-form: Seaborn usa las columnas como series
sns.lineplot(data=datos_wide.set_index("mes"), marker="o")
plt.title("Ventas mensuales (wide-form)")
plt.show()
Transformar datos de wide-form a long-form
La función pd.melt() convierte datos wide-form a long-form, que es el formato preferido por la mayoría de las funciones de Seaborn:
# Transformar wide-form a long-form
datos_long2 = pd.melt(
datos_wide,
id_vars=["mes"], # columnas que se mantienen fijas
var_name="persona", # nombre de la nueva columna de variables
value_name="ventas" # nombre de la nueva columna de valores
)
print(datos_long2)
mes persona ventas
0 Enero Ana 150
1 Febrero Ana 180
2 Marzo Ana 200
3 Enero Luis 120
4 Febrero Luis 160
5 Marzo Luis 190
Un ejemplo más complejo con el dataset de flights:
flights = sns.load_dataset("flights")
print("Long-form original:")
print(flights.head())
# Pivotar a wide-form
flights_wide = flights.pivot(index="month", columns="year", values="passengers")
print("\nWide-form:")
print(flights_wide.head())
# Seaborn puede visualizar directamente el formato wide-form en heatmap
plt.figure(figsize=(12, 6))
sns.heatmap(flights_wide, annot=True, fmt="d", cmap="YlOrRd", linewidths=0.5)
plt.title("Pasajeros por mes y año")
plt.show()
Cómo Seaborn infiere variables del DataFrame
Cuando pasas un DataFrame y nombres de columnas a las funciones de Seaborn, la biblioteca accede automáticamente a las columnas por nombre. Esto elimina la necesidad de extraer arrays manualmente:
penguins = sns.load_dataset("penguins")
# Seaborn accede a las columnas por nombre directamente
# No necesitas: x=penguins["bill_length_mm"], y=penguins["bill_depth_mm"]
sns.scatterplot(
data=penguins,
x="bill_length_mm", # nombre de columna como string
y="bill_depth_mm",
hue="species",
size="body_mass_g",
style="sex",
sizes=(30, 200),
alpha=0.7
)
plt.title("Dimensiones del pico de pingüinos")
plt.show()
Seaborn también infiere automáticamente las etiquetas de los ejes a partir de los nombres de las columnas, lo que reduce el código de etiquetado manual.
Datos con tipos categóricos de Pandas
Cuando una columna tiene tipo category en Pandas, Seaborn la trata de forma especial: respeta el orden definido en las categorías y muestra solo las categorías presentes en los datos:
tips = sns.load_dataset("tips")
# Definir el orden de los días como categoría
dias_ordenados = ["Thur", "Fri", "Sat", "Sun"]
tips["day"] = pd.Categorical(tips["day"], categories=dias_ordenados, ordered=True)
# Seaborn respetará el orden de las categorías
sns.boxplot(data=tips, x="day", y="total_bill", palette="Set2")
plt.title("Total de cuenta por día (con orden categórico)")
plt.show()
También es útil para controlar el orden en gráficos de barras y categóricos:
# Usar el parámetro order para controlar el orden sin necesidad de categorías
sns.countplot(
data=tips,
x="day",
order=["Thur", "Fri", "Sat", "Sun"],
hue="time",
palette="pastel"
)
plt.title("Conteo de visitas por día")
plt.show()
Trabajar con valores nulos
Seaborn ignora automáticamente los valores nulos (NaN) en la mayoría de las funciones, mostrando solo los datos disponibles. Sin embargo, es importante ser consciente de cómo afectan las estadísticas calculadas:
# El dataset penguins contiene valores nulos
penguins = sns.load_dataset("penguins")
print(f"Valores nulos por columna:")
print(penguins.isnull().sum())
# Seaborn maneja los nulos automáticamente
sns.histplot(data=penguins, x="bill_length_mm", hue="species", kde=True)
plt.title("Distribución del largo del pico (con nulos ignorados)")
plt.show()
# Para visualizar qué datos faltan
fig, ax = plt.subplots(figsize=(10, 4))
sns.heatmap(penguins.isnull(), cbar=False, yticklabels=False, cmap="viridis", ax=ax)
ax.set_title("Mapa de valores nulos en el dataset penguins")
plt.show()
Datos agrupados con groupby
Seaborn puede recibir el resultado de operaciones groupby de Pandas o datos previamente agregados:
# Calcular estadísticas agregadas antes de visualizar
import numpy as np
ventas_por_dia = (
tips.groupby("day")
.agg(
importe_medio=("total_bill", "mean"),
propina_media=("tip", "mean"),
num_cuentas=("total_bill", "count")
)
.reset_index()
)
print(ventas_por_dia)
# Visualizar datos ya agregados
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
sns.barplot(
data=ventas_por_dia,
x="day",
y="importe_medio",
order=["Thur", "Fri", "Sat", "Sun"],
palette="Blues_d",
ax=axes[0]
)
axes[0].set_title("Importe medio por día")
sns.scatterplot(
data=ventas_por_dia,
x="importe_medio",
y="propina_media",
size="num_cuentas",
sizes=(100, 500),
ax=axes[1]
)
axes[1].set_title("Importe medio vs propina media")
plt.tight_layout()
plt.show()
Datos de series temporales
Para datos temporales, Seaborn funciona directamente con columnas de tipo datetime de Pandas:
import numpy as np
rng = np.random.default_rng(seed=42)
# Crear un DataFrame de ventas diarias
fechas = pd.date_range(start="2025-01-01", end="2025-12-31", freq="D")
ventas_diarias = pd.DataFrame({
"fecha": fechas,
"ventas": rng.integers(50, 300, size=len(fechas)) + np.sin(np.arange(len(fechas)) / 30) * 50,
"canal": rng.choice(["Online", "Tienda"], size=len(fechas))
})
sns.lineplot(
data=ventas_diarias,
x="fecha",
y="ventas",
hue="canal",
errorbar=None
)
plt.title("Ventas diarias por canal en 2025")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Resumen: buenas prácticas con datos en Seaborn
- Usa formato long-form siempre que sea posible: una observación por fila, una variable por columna.
- Define tipos categóricos en Pandas cuando el orden de las categorías importa.
- No extraigas arrays manualmente: pasa el DataFrame completo y referencia las columnas por nombre.
- Comprueba los nulos antes de visualizar para entender su impacto en las estadísticas.
- Transforma con melt/stack cuando tus datos originales estén en formato wide-form.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Seaborn es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Seaborn
Explora más contenido relacionado con Seaborn y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Distinguir entre datos en formato long-form y wide-form. Transformar datos wide-form a long-form con pandas melt y stack. Comprender cómo Seaborn infiere las variables estéticas de los DataFrames. Usar datos agrupados y transformados directamente en las funciones de Seaborn. Trabajar con datos con valores nulos y tipos de datos categóricos.