Skip to main content

Reshaping and Pivot Tables

Reshaping changes representation, not the underlying observations. State the row grain—the meaning of one row—before and after the operation.

Choose the operation

NeedOperation
Unique long-to-wide mappingpivot
Long-to-wide with aggregationpivot_table
Wide-to-longmelt or wide_to_long
Move index levels between axesstack / unstack
Expand list-like cells to rowsexplode
Cross-tabulate categoriescrosstab
wide = observations.pivot(index="date", columns="metric", values="value")

summary = observations.pivot_table(
index="region",
columns="product",
values="revenue",
aggfunc="sum",
fill_value=0,
margins=True,
)

pivot raises when more than one value exists for an index/column pair. That is a useful grain check. Use pivot_table only when an aggregation is intentional, and choose the aggregation explicitly.

Return to tidy form

long = wide.reset_index().melt(
id_vars="date",
var_name="metric",
value_name="value",
)

After reshaping, verify row counts or key uniqueness and distinguish structural missing combinations from missing observed values. fill_value=0 is valid only when “no represented observation” truly means zero.

Source