Reshape Data with Pivot and Melt
Learn to reshape data with pivot and melt in this Python for data science tutorial.
Focus: reshape data with pivot and melt
Your data is messy. You've got a DataFrame that looks like a spreadsheet from 2004 — dates in rows, products in columns, and values scattered like confetti. Every time you try to plot it, run a statistical test, or feed it into a machine learning model, you hit a wall. The culprit? Your data is in the wrong shape. This lesson is your escape hatch.
Reshaping data with pivot and melt is the single most powerful skill in the pandas toolkit. pivot flips your data from long to wide, and melt does the opposite — turning wide data into tidy, analysis-ready rows. By the end of this lesson, you'll be able to reshape any dataset on command, and you'll understand exactly when to use each tool.
The problem this lesson solves
Real-world data rarely arrives in the shape you need. APIs return nested JSON, spreadsheets have one column per category, and survey exports put every answer in a separate row. Trying to analyze data in the wrong format is like trying to bake a cake with the ingredients still in the pantry — technically possible, but messy and error-prone.
Consider this: you have sales data where each row is a product and each column is a month. To plot a trend line, you need every month in a single column. Or you have a long format — one row per customer per purchase — but you need a pivot table with customers as rows and products as columns for a recommendation engine.
Without pivot and melt, you'd resort to manual loops, groupby gymnastics, or painful copy-paste in Excel. With them, you reshape your data in one clean line of code.
Why it matters now: As you progress in your data science journey, you'll spend 80% of your time cleaning and reshaping data. Master these two functions, and you'll cut your analysis time in half.
Core concept / mental model
Think of your data as a piece of clay. pivot and melt are your two most important sculpting tools.
pivot— takes long data (many rows, few columns) and makes it wide (fewer rows, more columns).melt— takes wide data (many columns, few rows) and makes it long (more rows, fewer columns).
A simple visual:
Long format (tidy) Wide format (summary)
───────────────────── ─────────────────────
| Year | Product | Sales | | Year | Apples | Oranges |
| 2023 | Apples | 100 | | 2023 | 100 | 150 |
| 2023 | Oranges | 150 | | 2024 | 120 | 180 |
| 2024 | Apples | 120 | ─────────────────────
| 2024 | Oranges | 180 |
─────────────────────
The tidy data principle: each variable is a column, each observation is a row. Most analysis tools love tidy data. melt gets you there; pivot is for when you need a summary view.
Think of melt as "unpivot" — it takes columns and turns them into rows, with two new columns: one for the old column names (variable) and one for their values (value). pivot is the reverse — it takes values from one column and spreads them out as new columns, using another column as the index.
How it works step by step
Let's break down both functions logically.
melt — from wide to long
- You have a DataFrame with many columns that represent different categories or time points.
- You decide which columns are identifier variables — the ones you want to keep as-is (e.g.,
Year). - All other columns become value variables — they get collapsed into a single column of values.
meltcreates two new columns,variableandvalue, and repeats the identifier rows accordingly.
Key parameters: id_vars, value_vars, var_name, value_name.
pivot — from long to wide
- You have a long DataFrame with one column that contains category names (e.g.,
Product) and another with values (e.g.,Sales). - You choose which column becomes the index (e.g.,
Year). - You choose which column's values become new column names (e.g.,
Product). - You specify which column holds the values to fill those new columns.
pivotreturns a new DataFrame with a row per index value, and one column per unique value in the pivot column.
Key parameters: index, columns, values.
Pro tip:
pivotis a pure reshape — it does not aggregate data. If you have duplicate index-column pairs, you'll get an error. Usepivot_tableif you need aggregation.
Hands-on walkthrough
Let's start with a sample dataset. We'll use a sales table in long format.
import pandas as pd
df_long = pd.DataFrame({
'Year': [2023, 2023, 2024, 2024],
'Product': ['Apples', 'Oranges', 'Apples', 'Oranges'],
'Sales': [100, 150, 120, 180]
})
print(df_long)
Output:
Year Product Sales
0 2023 Apples 100
1 2023 Oranges 150
2 2024 Apples 120
3 2024 Oranges 180
Now let's pivot it to get a summary with years as rows and products as columns.
pivoted = df_long.pivot(index='Year', columns='Product', values='Sales')
print(pivoted)
Output:
Product Apples Oranges
Year
2023 100 150
2024 120 180
Now, let's melt it back to long format. Suppose you receive a wide CSV file:
# Simulate a wide dataset
df_wide = pd.DataFrame({
'Year': [2023, 2024],
'Apples': [100, 120],
'Oranges': [150, 180]
})
melted = df_wide.melt(id_vars=['Year'], var_name='Product', value_name='Sales')
print(melted)
Output:
Year Product Sales
0 2023 Apples 100
1 2024 Apples 120
2 2023 Oranges 150
3 2024 Oranges 180
Notice how melt returns the same long format we started with — the two operations are inverses.
Real-world example: multiple value columns
What if you have both sales and profit? Use pivot_table to aggregate, or melt with value_vars to choose specific columns.
# Higher-dimensional pivot
df_multi = pd.DataFrame({
'Year': [2023, 2023, 2024, 2024],
'Product': ['Apples', 'Oranges', 'Apples', 'Oranges'],
'Sales': [100, 150, 120, 180],
'Profit': [20, 30, 25, 40]
})
pivot_multi = df_multi.pivot(index='Year', columns='Product', values='Sales')
print(pivot_multi)
Output:
Product Apples Oranges
Year
2023 100 150
2024 120 180
To keep both sales and profit, you can use pivot_table with aggfunc='mean' or set the index to a MultiIndex.
Compare options / when to choose what
Before you pick pivot or melt, ask yourself: What shape does my analysis need?
| Scenario | Use pivot |
Use melt |
|---|---|---|
| You need a crosstab summary | ✅ | ❌ |
| You need tidy rows for modeling | ❌ | ✅ |
| You have many category columns | ❌ | ✅ |
| You have duplicate index-column pairs | Use pivot_table |
Use melt + drop_duplicates |
You want to invert a melt |
✅ | ❌ |
| You need to aggregate duplicates | Use pivot_table |
Use groupby + agg |
Alternatives:
- pivot_table — adds aggregation (aggfunc) and handles duplicates.
- stack/unstack — reshape the index levels for MultiIndex DataFrames.
- groupby + agg — combine with pivot for complex summaries.
Troubleshooting & edge cases
Error: "Index contains duplicate entries"
This happens when your index and columns combination isn't unique.
# Duplicate rows cause this error
df = pd.DataFrame({
'Year': [2023, 2023],
'Product': ['Apples', 'Apples'],
'Sales': [100, 120]
})
# df.pivot(index='Year', columns='Product', values='Sales') # raises ValueError
Fix: Use pivot_table with aggfunc='sum' (or mean/min) to collapse duplicates.
Melt output columns are named variable and value
If you don't like the defaults, specify var_name and value_name.
Pivot resets index to a column
If you want Year back as a regular column, call reset_index().
pivoted.reset_index(inplace=True)
Missing values after pivot
If some combinations have no data, you'll get NaN. Use fillna(0) for a complete table.
Edge case:
pivot_tablefills missing values with NaN by default; you can passfill_value=0to avoid that.
What you learned & what's next
You've just mastered the two most powerful data reshaping tools in pandas. You can now:
- Explain why and when to use
pivotvsmelt - Reshape a long dataset to a wide summary using
pivot - Melt a wide dataset into a tidy long format
- Troubleshoot duplicate-index errors and missing values
What's next? In the next lesson, you'll combine datasets with merge and concat — the natural follow-up when you need to bring multiple DataFrames together after reshaping them.
Review this lesson by going back to the mental model anytime, and remember: every dataset has an ideal shape — you now know how to find it.
Practice recap
Grab any dataset you have — or use pd.DataFrame({'Year': [2021, 2021, 2022, 2022], 'City': ['A', 'B', 'A', 'B'], 'Revenue': [100, 200, 150, 250]}). First pivot it so the rows are years and columns are cities, then melt it back to a long format. Verify the original DataFrame matches after a pivot → melt cycle. Experiment with pivot_table to handle duplicates and fillna for missing data.
Common mistakes
- Forgetting that
pivotthrows an error on duplicate index-column pairs — usepivot_tableinstead. - Melt returns columns named
variableandvaluethat you forget to rename withvar_nameandvalue_name. - Calling
pivoton data that isn't already tidy — you still need unique rows per index-column combo. - Confusing
pivot(reshape) withpivot_table(reshape + aggregate) when you need summary stats.
Variations
- Use
pivot_tablewithaggfunc='sum'or'mean'to handle duplicate entries while aggregating. - Use
stack/unstackto reshape MultiIndex DataFrames without losing index structure. - Use
meltwithvalue_varsto select only a subset of columns for reshaping.
Real-world use cases
- Flattening wide survey responses into a tidy long format for statistical analysis in SciPy.
- Creating a pivot table from transaction logs to compare product sales across regions for a Tableau dashboard.
- Preparing a long-format time series from multiple CSV columns to feed into statsmodels for trend analysis.
Key takeaways
meltturns wide data into tidy long format — use it for analysis and modeling.pivotturns long data into a wide summary — perfect for reports and visualizations.pivot_tableis your friend when you have duplicate rows — it aggregates withaggfunc.- Always specify
id_varsinmeltto keep identifier columns intact. - Use
reset_index()afterpivotif you want the index back as a regular column.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.