Skip to content

Commit e0e19a3

Browse files
committed
Move .unstack() logic onto BlockManager and Block
1 parent c6fae5f commit e0e19a3

File tree

2 files changed

+37
-40
lines changed

2 files changed

+37
-40
lines changed

pandas/core/internals.py

+32
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,10 @@ def equals(self, other):
13121312
return False
13131313
return array_equivalent(self.values, other.values)
13141314

1315+
def _unstack(self, new_values, new_placement):
1316+
"""Return a list of unstacked blocks of self"""
1317+
return [make_block(new_values, placement=new_placement)]
1318+
13151319
def quantile(self, qs, interpolation='linear', axis=0, mgr=None):
13161320
"""
13171321
compute the quantiles of the
@@ -1554,6 +1558,12 @@ def _slice(self, slicer):
15541558
def _try_cast_result(self, result, dtype=None):
15551559
return result
15561560

1561+
def _unstack(self, new_values, new_placement):
1562+
# NonConsolidatable blocks can have a single item only, so we return
1563+
# one block per item
1564+
return [self.make_block_same_class(vals, [place])
1565+
for vals, place in zip(new_values.T, new_placement)]
1566+
15571567

15581568
class NumericBlock(Block):
15591569
__slots__ = ()
@@ -4066,6 +4076,28 @@ def canonicalize(block):
40664076
return all(block.equals(oblock)
40674077
for block, oblock in zip(self_blocks, other_blocks))
40684078

4079+
def unstack(self, unstacker):
4080+
"""Return blockmanager with all blocks unstacked"""
4081+
dummy = unstacker(np.empty((0, 0)), value_columns=self.items)
4082+
new_columns = dummy.get_new_columns()
4083+
new_index = dummy.get_new_index()
4084+
new_blocks = []
4085+
mask_blocks = np.zeros_like(new_columns, dtype=bool)
4086+
4087+
for blk in self.blocks:
4088+
bunstacker = unstacker(
4089+
blk.values.T, value_columns=self.items[blk.mgr_locs.indexer])
4090+
new_items = bunstacker.get_new_columns()
4091+
new_values, mask = bunstacker.get_new_values()
4092+
new_placement = new_columns.get_indexer(new_items)
4093+
mask_blocks[new_placement] = mask.any(0)
4094+
new_blocks.extend(blk._unstack(new_values, new_placement))
4095+
4096+
new_blocks = [b for b, keep in zip(new_blocks, mask_blocks) if keep]
4097+
new_axes = [new_columns[mask_blocks], new_index]
4098+
bm = BlockManager(new_blocks, new_axes)
4099+
return bm
4100+
40694101

40704102
class SingleBlockManager(BlockManager):
40714103
""" manage a single block with """

pandas/core/reshape/reshape.py

+5-40
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# pylint: disable=W0703,W0622,W0613,W0201
33
from pandas.compat import range, zip
44
from pandas import compat
5+
from functools import partial
56
import itertools
67
import re
78

@@ -466,48 +467,12 @@ def unstack(obj, level, fill_value=None):
466467

467468

468469
def _unstack_frame(obj, level, fill_value=None):
469-
from pandas.core.internals import BlockManager, make_block as _make_block
470-
471470
if obj._is_mixed_type:
472-
unstacker = _Unstacker(np.empty((0, 0)), # dummy
473-
obj.index, level=level,
474-
value_columns=obj.columns)
475-
new_columns = unstacker.get_new_columns()
476-
new_index = unstacker.get_new_index()
477-
new_axes = [new_columns, new_index]
478-
479-
new_blocks = []
480-
mask_blocks = np.zeros_like(new_columns, dtype=bool)
481-
for blk in obj._data.blocks:
482-
blk_items = obj._data.items[blk.mgr_locs.indexer]
483-
bunstacker = _Unstacker(blk.values.T, obj.index, level=level,
484-
value_columns=blk_items,
485-
fill_value=fill_value)
486-
new_items = bunstacker.get_new_columns()
487-
new_placement = new_columns.get_indexer(new_items)
488-
new_values, mask = bunstacker.get_new_values()
489-
490-
mask_blocks[new_placement] = mask.any(0)
491-
492-
# BlockManager can't handle SparseBlocks with multiple items,
493-
# so lets make one block for each item
494-
if is_sparse(blk.values):
495-
new_placement = [[i] for i in new_placement]
496-
new_values = new_values.T
497-
make_block = blk.make_block_same_class
498-
else:
499-
new_placement = [new_placement]
500-
new_values = [new_values.T]
501-
make_block = _make_block
502-
503-
for cols, placement in zip(new_values, new_placement):
504-
newb = make_block(cols, placement=placement)
505-
new_blocks.append(newb)
506-
471+
unstacker = partial(_Unstacker, index=obj.index,
472+
level=level, fill_value=fill_value)
473+
blocks = obj._data.unstack(unstacker)
507474
klass = type(obj)
508-
assert klass in (SparseDataFrame, DataFrame), klass
509-
result = klass(BlockManager(new_blocks, new_axes))
510-
return result.loc[:, mask_blocks]
475+
return klass(blocks)
511476
else:
512477
unstacker = _Unstacker(obj.values, obj.index, level=level,
513478
value_columns=obj.columns,

0 commit comments

Comments
 (0)