By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Reshaping data is the process of reorganizing a DataFrame’s structure—changing how rows, columns, and values are arranged—without altering the underlying data. Think of it like rearranging a spreadsheet: you might flip rows into columns, collapse multiple columns into key-value pairs, or expand nested data into a flat table.
2020_sales
2021_sales
year
sales
You’re building a sales dashboard for a retail client. Their raw data looks like this:
But your dashboard’s plotting library expects data in this format:
Without reshaping, your dashboard won’t render. This guide shows you how to fix it.
Jan_2023
Feb_2023
month
melt()
{"product_id": 101, "Jan_2023": 150}
{"product_id": 101, "month": "Jan_2023", "sales": 150}
pivot()
pivot_table()
sum
mean
ValueError: Index contains duplicate entries
stack()
unstack()
wide_to_long()
2023_Jan
2023_Feb
explode()
pandas
pip install pandas
You have a wide-format sales dataset (sales_wide.csv):
sales_wide.csv
product_id,Jan_2023,Feb_2023,Mar_2023 101,150,200,180 102,300,250,320 103,50,75,60
Goal: Convert it to long format for time-series analysis.
import pandas as pd df = pd.read_csv("sales_wide.csv") print(df.head())
Output:
product_id Jan_2023 Feb_2023 Mar_2023 0 101 150 200 180 1 102 300 250 320 2 103 50 75 60
df_long = df.melt( id_vars=["product_id"], # Columns to keep as-is value_vars=["Jan_2023", "Feb_2023", "Mar_2023"], # Columns to melt var_name="month", # New column for melted column names value_name="sales" # New column for melted values ) print(df_long.head())
product_id month sales 0 101 Jan_2023 150 1 102 Jan_2023 300 2 103 Jan_2023 50 3 101 Feb_2023 200 4 102 Feb_2023 250
Why This Works: - id_vars: Columns that stay as identifiers (e.g., product_id).- value_vars: Columns to "unpivot" into rows.- var_name: Name for the new column holding the original column names (month).- value_name: Name for the new column holding the original values (sales).
id_vars
product_id
value_vars
var_name
value_name
The month column has _2023—let’s remove it for cleaner analysis:
_2023
df_long["month"] = df_long["month"].str.replace("_2023", "") print(df_long.head())
product_id month sales 0 101 Jan 150 1 102 Jan 300 2 103 Jan 50 3 101 Feb 200 4 102 Feb 250
Now, let’s say you need to compare sales by product and month in a wide table:
df_wide = df_long.pivot( index="product_id", # Rows columns="month", # Columns values="sales" # Values to fill the table ) print(df_wide)
month Feb Jan Mar product_id 101 200 150 180 102 250 300 320 103 75 50 60
Key Notes: - pivot() fails if there are duplicate index/columns pairs. Use pivot_table() if duplicates exist.- The output is a MultiIndex DataFrame (columns are month, rows are product_id).
index
columns
Suppose you have duplicate entries (e.g., multiple sales records for the same product/month). pivot_table() handles this by aggregating:
# Example with duplicates df_dupes = pd.DataFrame({ "product_id": [101, 101, 102, 102], "month": ["Jan", "Jan", "Feb", "Feb"], "sales": [150, 200, 250, 300] }) df_pivot = df_dupes.pivot_table( index="product_id", columns="month", values="sales", aggfunc="sum" # Default is "mean" ) print(df_pivot)
month Feb Jan product_id 101 NaN 350 102 550 NaN
Let’s create a MultiIndex DataFrame and reshape it:
# Create a MultiIndex DataFrame index = pd.MultiIndex.from_tuples( [("101", "Jan"), ("101", "Feb"), ("102", "Jan"), ("102", "Feb")], names=["product_id", "month"] ) df_multi = pd.DataFrame({"sales": [150, 200, 300, 250]}, index=index) print(df_multi)
sales product_id month 101 Jan 150 Feb 200 102 Jan 300 Feb 250
Stack/Unstack:
# Stack: Pivot columns into rows (creates a Series) stacked = df_multi.stack() print(stacked)
product_id month 101 Jan sales 150 sales 200 102 Jan sales 300 sales 250 dtype: int64
# Unstack: Pivot rows into columns (back to DataFrame) unstacked = df_multi.unstack() print(unstacked)
sales month Feb Jan product_id 101 200 150 102 250 300
When to Use: - stack(): When you need to flatten a DataFrame for export or analysis.- unstack(): When you need to expand a MultiIndex for visualization.
If your columns follow a pattern (e.g., 2023_Jan, 2023_Feb), use wide_to_long():
df_prefixed = pd.DataFrame({ "product_id": [101, 102], "2023_Jan": [150, 300], "2023_Feb": [200, 250], "2024_Jan": [160, 310] }) df_long_prefixed = pd.wide_to_long( df_prefixed, stubnames=["2023", "2024"], # Prefixes to extract i="product_id", # Identifier column j="month", # New column for suffixes sep="_", # Separator between prefix and suffix suffix=".+" # Regex for suffix (matches anything) ) print(df_long_prefixed)
2023 2024 product_id month 101 Jan 150.0 NaN Feb 200.0 NaN 102 Jan 300.0 NaN Feb 250.0 NaN 101 Jan NaN 160.0 102 Jan NaN 310.0
Key Notes: - stubnames: The prefixes to extract (e.g., 2023, 2024).- suffix=".+": Matches any suffix after the prefix.
stubnames
2023
2024
suffix=".+"
apply()
dtype
category
python df_long["month"] = df_long["month"].astype("category")
python if df.duplicated(subset=["product_id", "month"]).any(): print("Warning: Duplicates found! Use pivot_table() instead.")
NaN
fillna(0)
dropna()
snake_case
# Convert to long format for time-series analysis
python def wide_to_long_sales(df, id_col="product_id"): return df.melt(id_vars=[id_col], var_name="month", value_name="sales")
SELECT * FROM sales WHERE month = 'Jan'
seaborn
plotly
aggfunc
aggfunc="sum"
TypeError: melt() got an unexpected keyword argument 'value_vars'
reindex()
df_pivot.reindex(columns=["Jan", "Feb"])
pivot_table(aggfunc="sum")
aggfunc="mean"
year_month
sep
["id", "2023_Q1", "2023_Q2", "2024_Q1"]
["id", "year", "quarter", "value"]
Answer: Use wide_to_long(): python pd.wide_to_long(df, stubnames=["2023", "2024"], i="id", j="quarter", sep="_", suffix="Q.")
python pd.wide_to_long(df, stubnames=["2023", "2024"], i="id", j="quarter", sep="_", suffix="Q.")
Question
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.