Skip to content

Commit 65171d9

Browse files
committed
BUG: support "fill_value" for ".unstack()" called with list of levels
closes #13971
1 parent aed9b92 commit 65171d9

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

doc/source/whatsnew/v0.21.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ Reshaping
10081008
- Bug in :func:`concat` where order of result index was unpredictable if it contained non-comparable elements (:issue:`17344`)
10091009
- Fixes regression when sorting by multiple columns on a ``datetime64`` dtype ``Series`` with ``NaT`` values (:issue:`16836`)
10101010
- Bug in :func:`pivot_table` where the result's columns did not preserve the categorical dtype of ``columns`` when ``dropna`` was ``False`` (:issue:`17842`)
1011+
- Bug in :func:`unstack` which, when called on a list of levels, would discard the ``fillna`` argument (:issue:`13971`)
10111012

10121013
Numeric
10131014
^^^^^^^

pandas/core/reshape/reshape.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def get_new_index(self):
292292
names=self.new_index_names, verify_integrity=False)
293293

294294

295-
def _unstack_multiple(data, clocs):
295+
def _unstack_multiple(data, clocs, fill_value=None):
296296
if len(clocs) == 0:
297297
return data
298298

@@ -330,7 +330,7 @@ def _unstack_multiple(data, clocs):
330330
if isinstance(data, Series):
331331
dummy = data.copy()
332332
dummy.index = dummy_index
333-
unstacked = dummy.unstack('__placeholder__')
333+
unstacked = dummy.unstack('__placeholder__', fill_value=fill_value)
334334
new_levels = clevels
335335
new_names = cnames
336336
new_labels = recons_labels
@@ -347,7 +347,7 @@ def _unstack_multiple(data, clocs):
347347
dummy = data.copy()
348348
dummy.index = dummy_index
349349

350-
unstacked = dummy.unstack('__placeholder__')
350+
unstacked = dummy.unstack('__placeholder__', fill_value=fill_value)
351351
if isinstance(unstacked, Series):
352352
unstcols = unstacked.index
353353
else:
@@ -460,7 +460,7 @@ def unstack(obj, level, fill_value=None):
460460
if len(level) != 1:
461461
# _unstack_multiple only handles MultiIndexes,
462462
# and isn't needed for a single level
463-
return _unstack_multiple(obj, level)
463+
return _unstack_multiple(obj, level, fill_value=fill_value)
464464
else:
465465
level = level[0]
466466

pandas/tests/frame/test_reshape.py

+23
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,29 @@ def test_unstack_fill(self):
154154
index=['x', 'y', 'z'], dtype=np.float)
155155
assert_frame_equal(result, expected)
156156

157+
# GH #13971: fill_value when unstacking multiple levels:
158+
f = DataFrame({'x': ['a', 'a', 'b'],
159+
'y': ['j', 'k', 'j'],
160+
'z': [0, 1, 2],
161+
'w': [0, 1, 2]}).set_index(['x', 'y', 'z'])
162+
unstacked = f.unstack(['x', 'y'], fill_value=0)
163+
key = ('w', 'b', 'j')
164+
expected = unstacked[key]
165+
result = pd.Series([0, 0, 2], index=unstacked.index, name=key)
166+
assert_series_equal(result, expected)
167+
stacked = unstacked.stack(['x', 'y'])
168+
stacked.index = stacked.index.reorder_levels(f.index.names)
169+
# Workaround for GH #17886:
170+
stacked = stacked.astype(int)
171+
result = stacked.loc[f.index]
172+
assert_frame_equal(result, f)
173+
174+
# From a series
175+
s = f['w']
176+
result = s.unstack(['x', 'y'], fill_value=0)
177+
expected = unstacked['w']
178+
assert_frame_equal(result, expected)
179+
157180
def test_unstack_fill_frame(self):
158181

159182
# From a dataframe

0 commit comments

Comments
 (0)