Skip to content

Commit 6d267a2

Browse files
committed
BUG: do not fail when stack()ing unsortable level
closes pandas-dev#18310
1 parent cfad581 commit 6d267a2

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
@@ -142,7 +142,8 @@ Sparse
142142
Reshaping
143143
^^^^^^^^^
144144

145-
-
145+
- Bug in :func:`DataFrame.stack` which fails trying to sort mixed type levels under Python 3 (:issue:`18310`)
146+
146147
-
147148
-
148149

pandas/core/indexes/multi.py

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

12931293
for lev, lab in zip(self.levels, self.labels):
12941294

1295-
if lev.is_monotonic:
1296-
new_levels.append(lev)
1297-
new_labels.append(lab)
1298-
continue
1299-
1300-
# indexer to reorder the levels
1301-
indexer = lev.argsort()
1302-
lev = lev.take(indexer)
1295+
if not lev.is_monotonic:
1296+
try:
1297+
# indexer to reorder the levels
1298+
indexer = lev.argsort()
1299+
except TypeError:
1300+
pass
1301+
else:
1302+
lev = lev.take(indexer)
13031303

1304-
# indexer to reorder the labels
1305-
indexer = _ensure_int64(indexer)
1306-
ri = lib.get_reverse_indexer(indexer, len(indexer))
1307-
lab = algos.take_1d(ri, lab)
1304+
# indexer to reorder the labels
1305+
indexer = _ensure_int64(indexer)
1306+
ri = lib.get_reverse_indexer(indexer, len(indexer))
1307+
lab = algos.take_1d(ri, lab)
13081308

13091309
new_levels.append(lev)
13101310
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)