22import itertools
33from typing import (
44 Any ,
5+ Callable ,
56 DefaultDict ,
67 Dict ,
78 List ,
@@ -324,18 +325,44 @@ def _verify_integrity(self) -> None:
324325 f"tot_items: { tot_items } "
325326 )
326327
327- def reduce (self : T , func ) -> T :
328+ def reduce (
329+ self : T , func : Callable , ignore_failures : bool = False
330+ ) -> Tuple [T , np .ndarray ]:
331+ """
332+ Apply reduction function blockwise, returning a single-row BlockManager.
333+
334+ Parameters
335+ ----------
336+ func : reduction function
337+ ignore_failures : bool, default False
338+ Whether to drop blocks where func raises TypeError.
339+
340+ Returns
341+ -------
342+ BlockManager
343+ np.ndarray
344+ Indexer of mgr_locs that are retained.
345+ """
328346 # If 2D, we assume that we're operating column-wise
329347 assert self .ndim == 2
330348
331349 res_blocks : List [Block ] = []
332350 for blk in self .blocks :
333- nbs = blk .reduce (func )
351+ nbs = blk .reduce (func , ignore_failures )
334352 res_blocks .extend (nbs )
335353
336- index = Index ([0 ]) # placeholder
337- new_mgr = BlockManager .from_blocks (res_blocks , [self .items , index ])
338- return new_mgr
354+ index = Index ([None ]) # placeholder
355+ if ignore_failures :
356+ if res_blocks :
357+ indexer = np .concatenate ([blk .mgr_locs .as_array for blk in res_blocks ])
358+ new_mgr = self ._combine (res_blocks , copy = False , index = index )
359+ else :
360+ indexer = []
361+ new_mgr = type (self ).from_blocks ([], [Index ([]), index ])
362+ else :
363+ indexer = np .arange (self .shape [0 ])
364+ new_mgr = type (self ).from_blocks (res_blocks , [self .items , index ])
365+ return new_mgr , indexer
339366
340367 def operate_blockwise (self , other : "BlockManager" , array_op ) -> "BlockManager" :
341368 """
@@ -698,7 +725,9 @@ def get_numeric_data(self, copy: bool = False) -> "BlockManager":
698725 """
699726 return self ._combine ([b for b in self .blocks if b .is_numeric ], copy )
700727
701- def _combine (self : T , blocks : List [Block ], copy : bool = True ) -> T :
728+ def _combine (
729+ self : T , blocks : List [Block ], copy : bool = True , index : Optional [Index ] = None
730+ ) -> T :
702731 """ return a new manager with the blocks """
703732 if len (blocks ) == 0 :
704733 return self .make_empty ()
@@ -714,6 +743,8 @@ def _combine(self: T, blocks: List[Block], copy: bool = True) -> T:
714743 new_blocks .append (b )
715744
716745 axes = list (self .axes )
746+ if index is not None :
747+ axes [- 1 ] = index
717748 axes [0 ] = self .items .take (indexer )
718749
719750 return type (self ).from_blocks (new_blocks , axes )
0 commit comments