Skip to content

Commit

Permalink
Backport PR #36371: BUG: Fix MultiIndex column stacking with dupe nam…
Browse files Browse the repository at this point in the history
…es (#36396)

Co-authored-by: Daniel Saxton <2658661+dsaxton@users.noreply.github.com>
  • Loading branch information
meeseeksmachine and dsaxton authored Sep 19, 2020
1 parent 711f923 commit eecc0d1
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 9 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.1.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Bug fixes
- Bug in :func:`read_spss` where passing a ``pathlib.Path`` as ``path`` would raise a ``TypeError`` (:issue:`33666`)
- Bug in :meth:`Series.str.startswith` and :meth:`Series.str.endswith` with ``category`` dtype not propagating ``na`` parameter (:issue:`36241`)
- Bug in :class:`Series` constructor where integer overflow would occur for sufficiently large scalar inputs when an index was provided (:issue:`36291`)
- Bug in :meth:`DataFrame.stack` raising a ``ValueError`` when stacking :class:`MultiIndex` columns based on position when the levels had duplicate names (:issue:`36353`)

.. ---------------------------------------------------------------------------
Expand Down
14 changes: 5 additions & 9 deletions pandas/core/reshape/reshape.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,19 +588,15 @@ def _stack_multi_columns(frame, level_num=-1, dropna=True):
def _convert_level_number(level_num, columns):
"""
Logic for converting the level number to something we can safely pass
to swaplevel:
to swaplevel.
We generally want to convert the level number into a level name, except
when columns do not have names, in which case we must leave as a level
number
If `level_num` matches a column name return the name from
position `level_num`, otherwise return `level_num`.
"""
if level_num in columns.names:
return columns.names[level_num]
else:
if columns.names[level_num] is None:
return level_num
else:
return columns.names[level_num]

return level_num

this = frame.copy()

Expand Down
13 changes: 13 additions & 0 deletions pandas/tests/frame/test_reshape.py
Original file line number Diff line number Diff line change
Expand Up @@ -1302,3 +1302,16 @@ def test_unstacking_multi_index_df():
),
)
tm.assert_frame_equal(result, expected)


def test_stack_positional_level_duplicate_column_names():
# https://github.com/pandas-dev/pandas/issues/36353
columns = pd.MultiIndex.from_product([("x", "y"), ("y", "z")], names=["a", "a"])
df = pd.DataFrame([[1, 1, 1, 1]], columns=columns)
result = df.stack(0)

new_columns = pd.Index(["y", "z"], name="a")
new_index = pd.MultiIndex.from_tuples([(0, "x"), (0, "y")], names=[None, "a"])
expected = pd.DataFrame([[1, 1], [1, 1]], index=new_index, columns=new_columns)

tm.assert_frame_equal(result, expected)

0 comments on commit eecc0d1

Please sign in to comment.