cswork / libraryOpen practice workspace

Articles

Pandas MultiIndex Interview Questions: Selection, Alignment, and Reshaping

Practice Pandas MultiIndex interview questions with loc and xs selections, label alignment, level broadcasting, and duplicate-aware stack and unstack examples.

A Pandas MultiIndex interview can go wrong even when every number looks reasonable. You select February, lose a level, add a Series in a different order, and reshape the result. The final table prints neatly, but its labels may describe a different calculation from the one you intended.

The useful habit is to predict the object type, index names, complete keys, and values at each step. A MultiIndex gives an axis multiple label levels; it does not turn arithmetic into positional matching or make duplicate observations disappear. This article follows one small dataset through selection, alignment, and reshaping so you can explain those boundaries aloud.

Evidence boundary: official pandas documentation supports the API behavior below. The exercises are original teaching examples, locally checked with pandas 3.0.5; the current online stable documentation identifies 3.0.6. They are not candidate-reported employer questions. For related implementation practice, begin with Use pandas to aggregate, pivot, and label, then apply the same label checks to its output.

Pandas MultiIndex interview questions: predict labels first

Before evaluating an expression, describe its contract. Which axis are you selecting? Is the key a complete tuple or only one level? Does the operation preserve the selected level? Will the result still have unique complete keys? These questions catch errors that a glance at numeric values misses.

Officially, pandas provides named levels and several constructors for hierarchical indexes. A practical mental model is a sequence of complete tuple keys, with reusable labels recorded for each level. However, complete keys need not be unique in an actual object: check index.is_unique when uniqueness matters. Level names identify dimensions; they are not data values. MultiIndex API

Use this original fixture throughout:

import pandas as pd

idx = pd.MultiIndex.from_tuples(
    [('East', 'Jan'), ('East', 'Feb'),
     ('West', 'Jan'), ('West', 'Feb')],
    names=['region', 'month'],
)
sales = pd.Series([10, 20, 30, 40], index=idx, name='sales')
df = sales.to_frame()

There are four observations, two index levels, and one DataFrame column. df.shape is (4, 1), not (2, 2). The repeated printed region label may be visually suppressed, but every row still has a full key. Likewise, from_product would construct all combinations of its input labels; from_tuples records the supplied pairs, which can be incomplete. Do not confuse a convenient display with the underlying domain.

Selection: a complete key, a partial key, and a cross-section

Consider three answers to “return February sales.” A complete key selects one observation; a partial region key selects multiple months; a cross-section can select the month level across regions. They answer different questions.

df.loc[('East', 'Feb'), 'sales']
# 20

df.loc['East', :]
# month-indexed DataFrame: Jan=10, Feb=20

df.xs('Feb', level='month')
# region-indexed DataFrame: East=20, West=40

df.xs('Feb', level='month', drop_level=False)
# keeps (East, Feb) and (West, Feb)

The scalar answer has no remaining index to inspect. The partial region selection removes the selected region level. The default cross-section removes the selected month level; drop_level=False retains it. That distinction matters when a later operation expects two-level keys rather than region labels alone. Official xs documentation also says cross-sections are not the interface for setting values. DataFrame.xs

For assignment, express the target on the original object in one .loc operation, for example df.loc[('East', 'Feb'), 'sales'] = 25. Do not assume changing a selected intermediate updates the parent. This article focuses on the target labels; the separate Pandas Copy-on-Write guide explains mutation behavior.

With DataFrame .loc, make row and column selectors explicit. The outer comma separates axes; a tuple inside the row selector describes a hierarchical key. A list of complete tuples selects specified pairs, whereas lists inside a tuple can select combinations across levels. Spell out which interpretation you want instead of hoping a compact expression is unambiguous. DataFrame.loc

A strong answer includes the resulting index names. “It returns East and West” is incomplete if the interviewer asks whether month survives.

Range slicing: sorting is part of the precondition

An exact lookup and a label range slice have different requirements. Official pandas guidance describes performance warnings for indexing beyond a MultiIndex's sorted depth and errors for some unsorted range slices. Avoid the blanket claim that every MultiIndex operation requires sorting. Advanced indexing

Our fixture stores January before February, which is chronological for this example but not alphabetical. Plain month strings do not encode calendar order. If a task needs chronological range semantics, define a suitable date or ordered representation; do not interpret string sorting as a calendar.

For a lexicographic exercise, make the ordering explicit:

ordered = df.sort_index()
part = ordered.loc[('East', 'Feb'):('West', 'Feb'), :]

After lexical sorting, the keys are East/Feb, East/Jan, West/Feb, West/Jan. The displayed slice includes the first three keys. Its endpoints are inclusive. A candidate who expects every month between February and January chronologically has changed the meaning of the labels without changing their representation.

After swaplevel, inspect ordering again. Swapping dimensions changes which label sequence comes first; it does not automatically sort the new hierarchy. Explain swaplevel(...).sort_index() as two separate decisions: rearrange dimensions, then establish a slice-compatible order. If order is irrelevant to a membership selection, a named-level Boolean mask can make that intent clearer than a range.

Alignment: reverse the rows and keep the keys

Here is the interview trap that exposes positional assumptions. Restrict sales to two complete keys and construct bonuses in the opposite order:

small = sales.loc[[('East', 'Jan'), ('West', 'Feb')]]
bonus = pd.Series(
    [4, 1],
    index=pd.MultiIndex.from_tuples(
        [('West', 'Feb'), ('East', 'Jan')],
        names=['region', 'month'],
    ),
)
result = small + bonus

The answer is East/Jan = 11 and West/Feb = 44. The first sales value does not receive the first bonus value. Arithmetic aligns compatible index labels; row order alone does not establish identity. The original figure below makes the reversed order visible.

Now change one bonus key to East/Mar. Ordinary addition uses the aligned label union and produces missing results wherever one operand lacks a matching value. Ask whether the business operation requires a union, an intersection, or an explicit rejection of unexpected keys. Those are different contracts, even when a fill value makes the output look complete.

Series.add(..., fill_value=0) can treat a missing operand as zero under its documented rules. It does not establish that an absent sales observation means zero sales. If both aligned operands are missing, the result remains missing. State the missing-data meaning before choosing the method. Series.add

Converting to NumPy removes label alignment from subsequent array arithmetic. That can be deliberate, but first assert the exact index order and compatible shapes. Otherwise, an apparently efficient shortcut replaces an identity-based calculation with a position-based one.

Broadcasting one adjustment across a named level

Suppose East gets a regional adjustment of 100 and West gets 200. The adjustment Series has a one-level index, while sales has region/month keys. Make the intended matching level explicit:

adjustment = pd.Series(
    [100, 200],
    index=pd.Index(['East', 'West'], name='region'),
)
adjusted = sales.add(adjustment, level='region')
# East/Jan=110, East/Feb=120
# West/Jan=230, West/Feb=240

The adjustment is repeated for existing observations with that region label. This does not generate missing month observations. Explicit level matching separates the regional rule from full-key matching and positional repetition. Pandas also provides alignment operations with a level parameter when you need to inspect the operands before calculating. DataFrame.align

Test an unknown region as a separate case. If the adjustment covers only East, West should not silently inherit East's value. Decide whether missing adjustments are errors, remain missing, or default to zero under an explicit business rule. Describe that decision in the answer, then assert it in code.

Reshaping: missing cells and duplicate keys are different problems

unstack('month') moves the month index level onto the column axis. For our Series, the result is a two-row DataFrame with February and January columns. East contains 20 and 10; West contains 40 and 30. The default column sorting explains the order. DataFrame.unstack

Remove West/Feb before unstacking. The wide table still has a West row and a February column because those labels exist elsewhere, but their intersection is missing. Filling that new cell with zero asserts a meaning the original data did not contain. In a reporting pipeline, distinguish “no recorded observation” from “recorded zero.”

Now append another East/Jan observation with value 7. The same output cell has two competing observations, so unstack cannot choose one and raises a duplicate-key error. Sorting cannot resolve this ambiguity. You must reject the duplicate, add an identifying dimension, or aggregate according to the task. Summing gives East/Jan = 17; choosing the latest record would require ordering evidence that this fixture lacks. Duplicate labels

stack moves a column level back into the row index. Current pandas 3.x uses the newer stack implementation by default; when future_stack=True, leave dropna and sort unspecified. Older snippets with legacy defaults may produce different missing-value or ordering behavior. DataFrame.stack

A complete-data round trip is a useful check, but compare normalized order and preserved labels rather than assuming identical display order. In our Series example, the unstack/stack result also loses the original sales name; restore it explicitly if that metadata belongs to the contract. With incomplete data, a wide representation can introduce explicit missing combinations. State whether your round-trip contract preserves observed pairs, all represented pairs, or only nonmissing values.

Sources and Further Reading

Research checked October 4, 2026. API details are version-sensitive; original fixture checks use pandas 3.0.5.