Reshaping
Stack and Unstack
Stack converts a wide DataFrame into a long Series by folding column labels into the row index, producing a MultiIndex. Unstack is the exact inverse — it lifts one index level back out to become column labels again.
By hand
With pandas
df.stack() folds the column labels into a new inner index level, returning
a Series with a two-level MultiIndex. stacked.unstack() reverses this,
restoring the original wide DataFrame.
naive.py
grid = {'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'y': 4}}
stacked = []
for row in sorted(grid):
for col in sorted(grid[row]):
stacked.append((row, col, grid[row][col]))
print('RESULT:', stacked)
library.py
import pandas as pd
from dalib.display import set_display
set_display()
df = pd.DataFrame({'x': [1, 3], 'y': [2, 4]}, index=['a', 'b'])
stacked = df.stack()
unstacked = stacked.unstack()
pairs = [(idx[0], idx[1], int(v)) for idx, v in stacked.items()]
print('df index:', df.index.tolist())
print('df columns:', df.columns.tolist())
print('stacked index:', stacked.index.tolist())
print('stacked values:', stacked.tolist())
print('unstacked columns:', unstacked.columns.tolist())
print('RESULT:', sorted(pairs))
df index: ['a', 'b']
df columns: ['x', 'y']
stacked index: [('a', 'x'), ('a', 'y'), ('b', 'x'), ('b', 'y')]
stacked values: [1, 2, 3, 4]
unstacked columns: ['x', 'y']
RESULT: [('a', 'x', 1), ('a', 'y', 2), ('b', 'x', 3), ('b', 'y', 4)]
Implementation notes
stack()moves the innermost column level into the innermost row index level. On a single-level column index this produces a two-level MultiIndex(original_row, col_label).unstack()(no args) reverses the laststack(). Pass a level number or name to control which level to un-pivot back to columns.- By default
stack()drops individualNaNentries from the resulting Series (dropna=True). Passdropna=Falseto keep them. - Cross-reference:
melt-wide-to-long(this chapter) for a similar wide-to- long transformation usingpd.melt;pivot-table-simplefor the reverse.