@@ -312,13 +312,14 @@ def ftype(self):
312
312
def merge (self , other ):
313
313
return _merge_blocks ([self , other ])
314
314
315
- def concat_same_type (self , to_concat ):
315
+ def concat_same_type (self , to_concat , placement = None ):
316
316
"""
317
317
Concatenate list of single blocks of the same type.
318
318
"""
319
- values = np .concatenate ([blk .values for blk in to_concat ])
319
+ values = np .concatenate ([blk .values for blk in to_concat ],
320
+ axis = self .ndim - 1 )
320
321
return self .make_block_same_class (
321
- values , placement = slice (0 , len (values ), 1 ))
322
+ values , placement = placement or slice (0 , len (values ), 1 ))
322
323
323
324
def reindex_axis (self , indexer , method = None , axis = 1 , fill_value = None ,
324
325
limit = None , mask_info = None ):
@@ -2415,7 +2416,7 @@ def to_native_types(self, slicer=None, na_rep='', quoting=None, **kwargs):
2415
2416
# we are expected to return a 2-d ndarray
2416
2417
return values .reshape (1 , len (values ))
2417
2418
2418
- def concat_same_type (self , to_concat ):
2419
+ def concat_same_type (self , to_concat , placement = None ):
2419
2420
"""
2420
2421
Concatenate list of single blocks of the same type.
2421
2422
"""
@@ -2424,9 +2425,9 @@ def concat_same_type(self, to_concat):
2424
2425
2425
2426
if is_categorical_dtype (values .dtype ):
2426
2427
return self .make_block_same_class (
2427
- values , placement = slice (0 , len (values ), 1 ))
2428
+ values , placement = placement or slice (0 , len (values ), 1 ))
2428
2429
else :
2429
- return make_block (values , placement = slice (0 , len (values ), 1 ))
2430
+ return make_block (values , placement = placement or slice (0 , len (values ), 1 ))
2430
2431
2431
2432
2432
2433
class DatetimeBlock (DatetimeLikeBlockMixin , Block ):
@@ -2705,7 +2706,7 @@ def shift(self, periods, axis=0, mgr=None):
2705
2706
return [self .make_block_same_class (new_values ,
2706
2707
placement = self .mgr_locs )]
2707
2708
2708
- def concat_same_type (self , to_concat ):
2709
+ def concat_same_type (self , to_concat , placement = None ):
2709
2710
"""
2710
2711
Concatenate list of single blocks of the same type.
2711
2712
"""
@@ -2714,9 +2715,9 @@ def concat_same_type(self, to_concat):
2714
2715
2715
2716
if is_datetimetz (values ):
2716
2717
return self .make_block_same_class (
2717
- values , placement = slice (0 , len (values ), 1 ))
2718
+ values , placement = placement or slice (0 , len (values ), 1 ))
2718
2719
else :
2719
- return make_block (values , placement = slice (0 , len (values ), 1 ))
2720
+ return make_block (values , placement = placement or slice (0 , len (values ), 1 ))
2720
2721
2721
2722
2722
2723
class SparseBlock (NonConsolidatableMixIn , Block ):
@@ -2885,15 +2886,15 @@ def sparse_reindex(self, new_index):
2885
2886
return self .make_block_same_class (values , sparse_index = new_index ,
2886
2887
placement = self .mgr_locs )
2887
2888
2888
- def concat_same_type (self , to_concat ):
2889
+ def concat_same_type (self , to_concat , placement = None ):
2889
2890
"""
2890
2891
Concatenate list of single blocks of the same type.
2891
2892
"""
2892
2893
to_concat = [blk .values for blk in to_concat ]
2893
2894
values = _concat ._concat_sparse (to_concat )
2894
2895
2895
2896
return self .make_block_same_class (
2896
- values , placement = slice (0 , len (values ), 1 ))
2897
+ values , placement = placement or slice (0 , len (values ), 1 ))
2897
2898
2898
2899
2899
2900
def make_block (values , placement , klass = None , ndim = None , dtype = None ,
@@ -5146,13 +5147,42 @@ def concatenate_block_managers(mgrs_indexers, axes, concat_axis, copy):
5146
5147
[get_mgr_concatenation_plan (mgr , indexers )
5147
5148
for mgr , indexers in mgrs_indexers ], concat_axis )
5148
5149
5149
- blocks = [make_block (
5150
- concatenate_join_units (join_units , concat_axis , copy = copy ),
5151
- placement = placement ) for placement , join_units in concat_plan ]
5150
+ blocks = []
5151
+
5152
+ for placement , join_units in concat_plan :
5153
+
5154
+ if is_uniform_join_units (join_units ):
5155
+ b = join_units [0 ].block .concat_same_type (
5156
+ [ju .block for ju in join_units ], placement = placement )
5157
+ else :
5158
+ b = make_block (
5159
+ concatenate_join_units (join_units , concat_axis , copy = copy ),
5160
+ placement = placement )
5161
+ blocks .append (b )
5152
5162
5153
5163
return BlockManager (blocks , axes )
5154
5164
5155
5165
5166
+ def is_uniform_join_units (join_units ):
5167
+ """
5168
+ Check if the join units consist of blocks of uniform type that can
5169
+ be concatenated using Block.concat_same_type instead of the generic
5170
+ concatenate_join_units (which uses `_concat._concat_compat`).
5171
+
5172
+ """
5173
+ return (
5174
+ # all blocks need to have the same type
5175
+ all ([type (ju .block ) is type (join_units [0 ].block ) for ju in join_units ]) # noqa
5176
+ # no blocks that would get missing values (can lead to type upcasts)
5177
+ and all ([not ju .is_na for ju in join_units ])
5178
+ # no blocks with indexers (as then the dimensions do not fit)
5179
+ and all ([not ju .indexers for ju in join_units ])
5180
+ # disregard Panels
5181
+ and all ([ju .block .ndim <= 2 for ju in join_units ])
5182
+ # only use this path when there is something to concatenate
5183
+ and len (join_units ) > 1 )
5184
+
5185
+
5156
5186
def get_empty_dtype_and_na (join_units ):
5157
5187
"""
5158
5188
Return dtype and N/A values to use when concatenating specified units.
0 commit comments