Skip to content
---
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ámetroDescripciónPor defecto
frameEl DataFrame a derretir (no se necesita al usar df.melt())Requerido
id_varsColumna(s) a mantener como variables identificadoras (no se derriten)None
value_varsColumna(s) a despivotar en filas. Si se omite, se usan todas las columnas que no estén en id_varsNone
var_nameNombre para la nueva columna que contiene los nombres originales de las columnas'variable'
value_nameNombre para la nueva columna que contiene los valores'value'
col_levelSi las columnas son un MultiIndex, el nivel que se va a derretirNone
ignore_indexSi es True, el resultado usa un nuevo índice entero. Si es False, se conserva el índice originalTrue

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     91

Cada 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      42

Esto 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     1200

Tanto 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     1400

Derretir 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       4

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

Ahora 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       92

Diferencia 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ónDirecciónIdeal paraDiferencia clave
melt()ancho a largoDespivotar columnas específicas en filasBasada en columnas; la más intuitiva para principiantes
stack()ancho a largoColapsar niveles de columnas en niveles del índiceBasada en índice; funciona con MultiIndex
wide_to_long()ancho a largoColumnas con un prefijo común y sufijo numérico (p. ej., score1, score2)Analiza automáticamente los “stub names”
pivot()largo a anchoExpandir valores en columnas (claves únicas)Inversa de melt()
unstack()largo a anchoExpandir niveles del índice en columnasInversa 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: int64

El 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     80

Usa 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ónTiempo aproximado
melt() con 50 columnas de valores~15 ms
Equivalente con stack()~10 ms
Bucle manual con concat()~500 ms

Consejos para mejor rendimiento:

  1. Especifica value_vars explícitamente — derretir solo las columnas que necesitas es más rápido que derretirlas todas.
  2. Usa ignore_index=True (por defecto) — preservar el índice original añade sobrecarga.
  3. Evita derretir y repivotar inmediatamente — si necesitas otro formato ancho, considera usar pivot_table() o rename() directamente en lugar de un “round-trip”.
  4. 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 object

Para 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_vars para especificar qué columnas mantener como identificadores.
  • Usa value_vars para controlar qué columnas se derriten. Omítelo para derretir todo excepto los identificadores.
  • Usa var_name y value_name para dar nombres significativos a las columnas de salida.
  • Melt y pivot son inversas — usa melt() para pasar de ancho a largo y pivot() para pasar de largo a ancho.
  • Elige melt() sobre stack() 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.

📚