Skip to content

Commit f7df0ff

Browse files
toobazjreback
authored andcommitted
BUG: do not fail when stack()ing unsortable level (pandas-dev#18363)
closes pandas-dev#18310
1 parent d5ffb1f commit f7df0ff

File tree

3 files changed

+38
-13
lines changed

3 files changed

+38
-13
lines changed

doc/source/whatsnew/v0.22.0.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ Sparse
218218
Reshaping
219219
^^^^^^^^^
220220

221-
-
221+
- Bug in :func:`DataFrame.stack` which fails trying to sort mixed type levels under Python 3 (:issue:`18310`)
222+
222223
-
223224
-
224225

pandas/core/indexes/multi.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -1320,19 +1320,19 @@ def _sort_levels_monotonic(self):
13201320

13211321
for lev, lab in zip(self.levels, self.labels):
13221322

1323-
if lev.is_monotonic:
1324-
new_levels.append(lev)
1325-
new_labels.append(lab)
1326-
continue
1327-
1328-
# indexer to reorder the levels
1329-
indexer = lev.argsort()
1330-
lev = lev.take(indexer)
1323+
if not lev.is_monotonic:
1324+
try:
1325+
# indexer to reorder the levels
1326+
indexer = lev.argsort()
1327+
except TypeError:
1328+
pass
1329+
else:
1330+
lev = lev.take(indexer)
13311331

1332-
# indexer to reorder the labels
1333-
indexer = _ensure_int64(indexer)
1334-
ri = lib.get_reverse_indexer(indexer, len(indexer))
1335-
lab = algos.take_1d(ri, lab)
1332+
# indexer to reorder the labels
1333+
indexer = _ensure_int64(indexer)
1334+
ri = lib.get_reverse_indexer(indexer, len(indexer))
1335+
lab = algos.take_1d(ri, lab)
13361336

13371337
new_levels.append(lev)
13381338
new_labels.append(lab)

pandas/tests/frame/test_reshape.py

+24
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,30 @@ def test_stack_unstack(self):
133133
assert_frame_equal(unstacked_cols.T, df)
134134
assert_frame_equal(unstacked_cols_df['bar'].T, df)
135135

136+
def test_stack_mixed_level(self):
137+
# GH 18310
138+
levels = [range(3), [3, 'a', 'b'], [1, 2]]
139+
140+
# flat columns:
141+
df = DataFrame(1, index=levels[0], columns=levels[1])
142+
result = df.stack()
143+
expected = Series(1, index=MultiIndex.from_product(levels[:2]))
144+
assert_series_equal(result, expected)
145+
146+
# MultiIndex columns:
147+
df = DataFrame(1, index=levels[0],
148+
columns=MultiIndex.from_product(levels[1:]))
149+
result = df.stack(1)
150+
expected = DataFrame(1, index=MultiIndex.from_product([levels[0],
151+
levels[2]]),
152+
columns=levels[1])
153+
assert_frame_equal(result, expected)
154+
155+
# as above, but used labels in level are actually of homogeneous type
156+
result = df[['a', 'b']].stack(1)
157+
expected = expected[['a', 'b']]
158+
assert_frame_equal(result, expected)
159+
136160
def test_unstack_fill(self):
137161

138162
# GH #9746: fill_value keyword argument for Series

0 commit comments

Comments
 (0)