---
title: "Pandas Melt: Reestructurar datos anchos a formato largo (Guía completa)"
description: "Aprende a usar pandas melt() para despivotar DataFrames de formato ancho a formato largo. Cubre id_vars, value_vars, melt con múltiples niveles y ejemplos reales de reestructuración."
date: 2026-02-12
author: soren
ogImage:
language: en
tag: "Pandas, Melt, Data Reshaping, DataFrame, Python"
---
# Pandas Melt: Reestructurar datos anchos a formato largo (Guía completa)
import BlogHeader from '../../../components/blog-header';
<BlogHeader />
Tienes una hoja de cálculo donde cada mes es una columna separada: January, February, March, hasta December. Doce columnas de cifras de ingresos, y necesitas graficar una serie temporal, ejecutar un groupby o alimentar los datos a un modelo de machine learning. Ninguna de esas operaciones funciona bien con datos en formato ancho. Necesitas una columna para el nombre del mes y otra para el valor de ingresos. Esa transformación —convertir columnas en filas— es exactamente lo que hace **pandas melt**.
El problema empeora rápido. Los datasets anchos con decenas o cientos de columnas son comunes en datos de encuestas, lecturas de sensores, reportes financieros y exportaciones pivotadas desde Excel o SQL. Reestructurarlos manualmente es tedioso y propenso a errores. Cada columna extra que necesitas despivotar significa más código repetitivo si intentas hacerlo sin la herramienta adecuada.
La función `pd.melt()` resuelve esto en una sola llamada. Toma un DataFrame ancho y lo “derrite” a formato largo convirtiendo columnas seleccionadas en filas, preservando intactas tus columnas identificadoras. Esta guía cubre la sintaxis completa, cada parámetro, ejemplos prácticos de escenarios del mundo real y comparaciones con funciones relacionadas de reestructuración como `pivot`, `stack` y `wide_to_long`.
import BlogSuggestion from '../../../components/blog-suggestion';
<BlogSuggestion />
## Qué hace pd.melt()
`pd.melt()` despivota (unpivot) un DataFrame de formato ancho a formato largo. En formato ancho, cada variable tiene su propia columna. En formato largo (también llamado formato “tidy”), hay una columna para los nombres de variable y otra para los valores.
Aquí está la transformación conceptual:
**Formato ancho (antes de melt):**
| student | math | science | english |
|---------|------|---------|---------|
| Alice | 90 | 85 | 88 |
| Bob | 78 | 92 | 80 |
**Formato largo (después de melt):**
| student | subject | score |
|---------|---------|-------|
| Alice | math | 90 |
| Alice | science | 85 |
| Alice | english | 88 |
| Bob | math | 78 |
| Bob | science | 92 |
| Bob | english | 80 |
La columna `student` se conserva como identificador, mientras que las tres columnas de materias se derriten en dos columnas: una que contiene el nombre de la materia y otra que contiene la calificación.
## Sintaxis y parámetros de pd.melt()
```python copy
pd.melt(frame, id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)También puedes llamarlo como un método del propio DataFrame:
df.melt(id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)Referencia de parámetros
| Parámetro | Descripción | Por defecto |
|---|---|---|
frame | El DataFrame a derretir (no se necesita al usar df.melt()) | Requerido |
id_vars | Columna(s) a mantener como variables identificadoras (no se derriten) | None |
value_vars | Columna(s) a despivotar en filas. Si se omite, se usan todas las columnas que no estén en id_vars | None |
var_name | Nombre para la nueva columna que contiene los nombres originales de las columnas | 'variable' |
value_name | Nombre para la nueva columna que contiene los valores | 'value' |
col_level | Si las columnas son un MultiIndex, el nivel que se va a derretir | None |
ignore_index | Si es True, el resultado usa un nuevo índice entero. Si es False, se conserva el índice original | True |
Ejemplo básico: Calificaciones de estudiantes
Comienza con el ejemplo de calificaciones de estudiantes de arriba:
import pandas as pd
grades = pd.DataFrame({
'student': ['Alice', 'Bob', 'Charlie'],
'math': [90, 78, 85],
'science': [85, 92, 88],
'english': [88, 80, 91]
})
long = pd.melt(grades, id_vars=['student'], value_vars=['math', 'science', 'english'],
var_name='subject', value_name='score')
print(long)Salida:
student subject score
0 Alice math 90
1 Bob math 78
2 Charlie math 85
3 Alice science 85
4 Bob science 92
5 Charlie science 88
6 Alice english 88
7 Bob english 80
8 Charlie english 91Cada fila ahora representa una combinación estudiante-materia. El DataFrame original 3x4 (3 filas, 4 columnas) se convierte en un DataFrame 9x3 (9 filas, 3 columnas).
Omitir value_vars
Si omites value_vars, pandas derrite cada columna que no esté listada en id_vars:
long = grades.melt(id_vars=['student'], var_name='subject', value_name='score')
print(long)Esto produce el mismo resultado que el ejemplo anterior. Omitir value_vars es conveniente cuando quieres derretir todas las columnas que no son identificadoras.
Derretir sin id_vars
También puedes derretir sin especificar columnas identificadoras. Esto coloca cada columna en el par variable/valor:
temperatures = pd.DataFrame({
'Jan': [30, 28],
'Feb': [32, 31],
'Mar': [45, 42]
})
long = temperatures.melt(var_name='month', value_name='temp_f')
print(long)Salida:
month temp_f
0 Jan 30
1 Jan 28
2 Feb 32
3 Feb 31
4 Mar 45
5 Mar 42Esto es útil cuando cada columna es una medición y no hay identificador que preservar.
Múltiples columnas identificadoras
Los datasets reales a menudo tienen más de un identificador. Puedes pasar una lista de nombres de columnas a id_vars:
sales = pd.DataFrame({
'region': ['North', 'South', 'North', 'South'],
'product': ['Widget', 'Widget', 'Gadget', 'Gadget'],
'q1_revenue': [1200, 1500, 800, 950],
'q2_revenue': [1400, 1600, 900, 1100],
'q3_revenue': [1100, 1450, 850, 1000],
'q4_revenue': [1500, 1700, 1000, 1200]
})
long_sales = sales.melt(
id_vars=['region', 'product'],
var_name='quarter',
value_name='revenue'
)
print(long_sales)Salida:
region product quarter revenue
0 North Widget q1_revenue 1200
1 South Widget q1_revenue 1500
2 North Gadget q1_revenue 800
3 South Gadget q1_revenue 950
4 North Widget q2_revenue 1400
5 South Widget q2_revenue 1600
6 North Gadget q2_revenue 900
7 South Gadget q2_revenue 1100
8 North Widget q3_revenue 1100
9 South Widget q3_revenue 1450
10 North Gadget q3_revenue 850
11 South Gadget q3_revenue 1000
12 North Widget q4_revenue 1500
13 South Widget q4_revenue 1700
14 North Gadget q4_revenue 1000
15 South Gadget q4_revenue 1200Tanto region como product se preservan en cada fila. Las cuatro columnas trimestrales se colapsan en dos columnas.
Limpieza después de melt
Después de derretir, la columna variable a menudo contiene cadenas que quieres limpiar. En el ejemplo de arriba, la columna de trimestre tiene valores como q1_revenue en lugar de solo Q1. Usa operaciones de strings para arreglarlo:
long_sales['quarter'] = long_sales['quarter'].str.replace('_revenue', '').str.upper()
print(long_sales.head())Salida:
region product quarter revenue
0 North Widget Q1 1200
1 South Widget Q1 1500
2 North Gadget Q1 800
3 South Gadget Q1 950
4 North Widget Q2 1400Derretir solo columnas seleccionadas
A veces solo quieres derretir un subconjunto de columnas. Especifícalas explícitamente en value_vars:
survey = pd.DataFrame({
'respondent': ['R1', 'R2', 'R3'],
'age': [25, 34, 42],
'q1_satisfaction': [4, 5, 3],
'q2_satisfaction': [3, 4, 5],
'q3_satisfaction': [5, 3, 4],
'income': [50000, 75000, 60000]
})
# Only melt the satisfaction columns, keep age and income as identifiers
long_survey = survey.melt(
id_vars=['respondent', 'age', 'income'],
value_vars=['q1_satisfaction', 'q2_satisfaction', 'q3_satisfaction'],
var_name='question',
value_name='rating'
)
print(long_survey)Salida:
respondent age income question rating
0 R1 25 50000 q1_satisfaction 4
1 R2 34 75000 q1_satisfaction 5
2 R3 42 60000 q1_satisfaction 3
3 R1 25 50000 q2_satisfaction 3
4 R2 34 75000 q2_satisfaction 4
5 R3 42 60000 q2_satisfaction 5
6 R1 25 50000 q3_satisfaction 5
7 R2 34 75000 q3_satisfaction 3
8 R3 42 60000 q3_satisfaction 4La columna income se mantiene como identificadora aunque no forme parte de las columnas derretidas.
Ejemplo del mundo real: Datos de series temporales
Los datos financieros y económicos a menudo llegan en formato ancho con fechas como encabezados de columna. Derretirlos los convierte en una serie temporal fácil de graficar:
import pandas as pd
gdp = pd.DataFrame({
'country': ['USA', 'UK', 'Germany'],
'2020': [20.94, 2.71, 3.89],
'2021': [23.00, 3.12, 4.26],
'2022': [25.46, 3.07, 4.07],
'2023': [27.36, 3.33, 4.46]
})
gdp_long = gdp.melt(id_vars=['country'], var_name='year', value_name='gdp_trillion_usd')
gdp_long['year'] = gdp_long['year'].astype(int)
gdp_long = gdp_long.sort_values(['country', 'year']).reset_index(drop=True)
print(gdp_long)Salida:
country year gdp_trillion_usd
0 Germany 2020 3.89
1 Germany 2021 4.26
2 Germany 2022 4.07
3 Germany 2023 4.46
4 UK 2020 2.71
5 UK 2021 3.12
6 UK 2022 3.07
7 UK 2023 3.33
8 USA 2020 20.94
9 USA 2021 23.00
10 USA 2022 25.46
11 USA 2023 27.36Ahora puedes graficar fácilmente el GDP a lo largo del tiempo, agrupar por país o calcular crecimiento interanual.
Melt con columnas MultiIndex
Si tu DataFrame tiene encabezados de columna multinivel, usa el parámetro col_level para especificar qué nivel derretir:
arrays = [['score', 'score', 'attendance', 'attendance'],
['midterm', 'final', 'midterm', 'final']]
columns = pd.MultiIndex.from_arrays(arrays, names=['metric', 'exam'])
data = pd.DataFrame([[85, 90, 95, 100], [78, 82, 90, 88]],
index=['Alice', 'Bob'], columns=columns)
# Melt the top level
melted = data.melt(col_level=0, var_name='metric', value_name='value', ignore_index=False)
print(melted)Para escenarios complejos multinivel, puede que necesites aplanar las columnas primero usando droplevel() o uniendo niveles con un guion bajo antes de derretir.
Melt vs Pivot: Operaciones inversas
melt() y pivot() son operaciones inversas. Melt convierte de ancho a largo. Pivot convierte de largo a ancho.
import pandas as pd
# Start wide
wide = pd.DataFrame({
'name': ['Alice', 'Bob'],
'math': [90, 78],
'science': [85, 92]
})
# Melt: wide -> long
long = wide.melt(id_vars='name', var_name='subject', value_name='score')
print("Long format:")
print(long)
# Pivot: long -> wide (round-trip)
back_to_wide = long.pivot(index='name', columns='subject', values='score').reset_index()
back_to_wide.columns.name = None
print("\nBack to wide format:")
print(back_to_wide)Salida:
Long format:
name subject score
0 Alice math 90
1 Bob math 78
2 Alice science 85
3 Bob science 92
Back to wide format:
name math science
0 Alice 90 85
1 Bob 78 92Diferencia clave: pivot() requiere combinaciones únicas de índice-columna. Si tus datos largos tienen duplicados, usa pivot_table() con una función de agregación en su lugar.
Melt vs Stack vs wide_to_long
Pandas ofrece varias funciones para reestructurar. Aquí tienes cuándo usar cada una:
| Función | Dirección | Ideal para | Diferencia clave |
|---|---|---|---|
melt() | ancho a largo | Despivotar columnas específicas en filas | Basada en columnas; la más intuitiva para principiantes |
stack() | ancho a largo | Colapsar niveles de columnas en niveles del índice | Basada en índice; funciona con MultiIndex |
wide_to_long() | ancho a largo | Columnas con un prefijo común y sufijo numérico (p. ej., score1, score2) | Analiza automáticamente los “stub names” |
pivot() | largo a ancho | Expandir valores en columnas (claves únicas) | Inversa de melt() |
unstack() | largo a ancho | Expandir niveles del índice en columnas | Inversa de stack() |
Cuándo usar stack() en su lugar
stack() opera sobre el índice de columnas y lo empuja hacia el índice de filas. Es más útil cuando ya estás trabajando con un MultiIndex y quieres reestructurar a nivel de índice:
wide = pd.DataFrame({
'math': [90, 78],
'science': [85, 92]
}, index=['Alice', 'Bob'])
stacked = wide.stack()
print(stacked)Salida:
Alice math 90
science 85
Bob math 78
science 92
dtype: int64El resultado es una Series con MultiIndex, no un DataFrame con columnas con nombre como produce melt(). Usa melt() cuando quieras una salida limpia en DataFrame con columnas explícitamente nombradas.
Cuándo usar wide_to_long()
wide_to_long() está diseñado para columnas que siguen un patrón de nombres como score1, score2, score3:
df = pd.DataFrame({
'student': ['Alice', 'Bob'],
'score1': [90, 78],
'score2': [85, 92],
'score3': [88, 80]
})
long = pd.wide_to_long(df, stubnames='score', i='student', j='exam_num')
print(long.reset_index())Salida:
student exam_num score
0 Alice 1 90
1 Alice 2 85
2 Alice 3 88
3 Bob 1 78
4 Bob 2 92
5 Bob 3 80Usa wide_to_long() cuando tus columnas tengan un patrón consistente prefijo-sufijo. De lo contrario, melt() es más flexible.
Consideraciones de rendimiento
Para la mayoría de los datasets (por debajo de unos pocos millones de filas), melt() es lo suficientemente rápido. Aquí hay benchmarks en un DataFrame con 100,000 filas y 50 columnas que se derriten:
| Operación | Tiempo aproximado |
|---|---|
melt() con 50 columnas de valores | ~15 ms |
Equivalente con stack() | ~10 ms |
Bucle manual con concat() | ~500 ms |
Consejos para mejor rendimiento:
- Especifica
value_varsexplícitamente — derretir solo las columnas que necesitas es más rápido que derretirlas todas. - Usa
ignore_index=True(por defecto) — preservar el índice original añade sobrecarga. - Evita derretir y repivotar inmediatamente — si necesitas otro formato ancho, considera usar
pivot_table()orename()directamente en lugar de un “round-trip”. - Para DataFrames muy grandes (100M+ filas después de melt), considera usar polars o Dask, que ofrecen evaluación perezosa y procesamiento en paralelo.
# Only melt the columns you actually need
long = df.melt(
id_vars=['id'],
value_vars=['col_a', 'col_b', 'col_c'], # Not all 50 columns
var_name='metric',
value_name='reading'
)Errores comunes y cómo solucionarlos
1. KeyError: Column Not Found
Esto ocurre cuando un nombre de columna en id_vars o value_vars no existe en el DataFrame:
# Wrong: column name has a typo
long = df.melt(id_vars=['stduent']) # KeyError
# Fix: check column names first
print(df.columns.tolist())2. Filas duplicadas que no esperabas
Melt por sí mismo no crea filas duplicadas: crea una fila por combinación de variables identificadoras. Si ves duplicados, significa que tus datos originales tenían filas identificadoras duplicadas:
# Check for duplicates in your id columns
print(df.duplicated(subset=['student']).sum())3. Tipos de datos mezclados en la columna de valores
Cuando derrites columnas de diferentes dtypes (p. ej., algunas son int64 y otras son float64), pandas promueve (upcast) la columna de valores al tipo más general. Si derrites una mezcla de columnas numéricas y de texto, la columna de valores se convierte en dtype object:
df = pd.DataFrame({
'id': [1, 2],
'score': [90, 85],
'grade': ['A', 'B']
})
long = df.melt(id_vars='id')
print(long.dtypes)
# variable object
# value object <-- both score and grade become objectPara evitar esto, derrite por separado las columnas numéricas y las de texto.
Visualiza datos derretidos con PyGWalker
Después de reestructurar tus datos de formato ancho a formato largo, el siguiente paso natural es explorar el resultado visualmente: revisar distribuciones, comparar grupos o detectar outliers. PyGWalker (opens in a new tab) es una librería open-source de Python que convierte cualquier DataFrame de pandas en una interfaz interactiva de exploración visual tipo Tableau dentro de Jupyter Notebook.
import pandas as pd
import pygwalker as pyg
# Melt your wide data into long format
grades = pd.DataFrame({
'student': ['Alice', 'Bob', 'Charlie', 'Diana'],
'math': [90, 78, 85, 92],
'science': [85, 92, 88, 79],
'english': [88, 80, 91, 84]
})
long = grades.melt(id_vars='student', var_name='subject', value_name='score')
# Launch interactive visualization
walker = pyg.walk(long)Con PyGWalker, puedes arrastrar subject al eje x y score al eje y, y luego colorear por student para comparar al instante el rendimiento entre materias, sin necesidad de escribir código de gráficos. Soporta gráficos de barras, dispersión, box plots y más, todo mediante drag-and-drop.
Prueba PyGWalker en Google Colab (opens in a new tab), Kaggle (opens in a new tab), o instala con
pip install pygwalker.
FAQ
¿Qué hace pandas melt?
Pandas melt() reestructura un DataFrame de formato ancho a formato largo. Toma columnas y las convierte en filas, creando dos nuevas columnas: una para los nombres originales de las columnas (variable) y otra para los valores. Esto también se conoce como “unpivoting”.
¿Cuál es la diferencia entre melt y pivot en pandas?
melt() convierte de formato ancho a formato largo (las columnas se convierten en filas). pivot() hace lo contrario: convierte de formato largo a formato ancho (las filas se convierten en columnas). Son operaciones inversas. Si derrites un DataFrame y luego haces pivot del resultado usando los mismos parámetros, recuperas el DataFrame original.
¿Cuándo debería usar melt vs stack en pandas?
Usa melt() cuando quieras un DataFrame limpio con columnas con nombre y control explícito sobre qué columnas despivotar. Usa stack() cuando estés trabajando con columnas MultiIndex y quieras empujar niveles de columnas hacia el índice de filas. melt() es más intuitivo para principiantes; stack() es más potente para reestructuración jerárquica.
¿Cómo derrito múltiples columnas en pandas?
Pasa una lista de nombres de columnas al parámetro value_vars: df.melt(id_vars=['id'], value_vars=['col_a', 'col_b', 'col_c']). Todas las columnas listadas se despivotarán en filas. Si omites value_vars, pandas derrite todas las columnas que no estén listadas en id_vars.
¿Puedo derretir un DataFrame con nombres de columnas duplicados?
Pandas derretirá el DataFrame, pero el resultado puede ser confuso porque la columna variable tendrá valores duplicados. Renombra primero las columnas duplicadas usando df.columns = [...] o df.rename() para evitar ambigüedad.
¿Cómo revierto una operación melt en pandas?
Usa pivot() o pivot_table() para convertir los datos derretidos (largos) de vuelta a formato ancho: long.pivot(index='id', columns='variable', values='value'). Usa pivot_table() si hay combinaciones duplicadas de índice-columna que requieran agregación.
Conclusión
La función melt() de pandas es la forma estándar de convertir DataFrames en formato ancho a formato largo (tidy) en Python. Puntos clave:
- Usa
id_varspara especificar qué columnas mantener como identificadores. - Usa
value_varspara controlar qué columnas se derriten. Omítelo para derretir todo excepto los identificadores. - Usa
var_nameyvalue_namepara dar nombres significativos a las columnas de salida. - Melt y pivot son inversas — usa
melt()para pasar de ancho a largo ypivot()para pasar de largo a ancho. - Elige
melt()sobrestack()cuando quieras un DataFrame plano con nombres de columna explícitos en lugar de una Series con MultiIndex. - Limpia después de derretir — usa métodos de strings en la columna de variable para quitar prefijos, sufijos o reformatear valores.
Después de reestructurar tus datos, herramientas como PyGWalker (opens in a new tab) te permiten explorar el resultado visualmente sin escribir código de gráficos, haciendo que el flujo de trabajo de análisis sea más rápido e intuitivo.