@@ -637,8 +637,25 @@ class DataFrame(NDFrame, OpsMixin):
637
637
def _constructor (self ) -> Callable [..., DataFrame ]:
638
638
return DataFrame
639
639
640
+ def _constructor_from_mgr (self , mgr , axes ):
641
+ if self ._constructor is DataFrame :
642
+ # we are pandas.DataFrame (or a subclass that doesn't override _constructor)
643
+ return self ._from_mgr (mgr , axes = axes )
644
+ else :
645
+ assert axes is mgr .axes
646
+ return self ._constructor (mgr )
647
+
640
648
_constructor_sliced : Callable [..., Series ] = Series
641
649
650
+ def _sliced_from_mgr (self , mgr , axes ) -> Series :
651
+ return Series ._from_mgr (mgr , axes )
652
+
653
+ def _constructor_sliced_from_mgr (self , mgr , axes ):
654
+ if self ._constructor_sliced is Series :
655
+ return self ._sliced_from_mgr (mgr , axes )
656
+ assert axes is mgr .axes
657
+ return self ._constructor_sliced (mgr )
658
+
642
659
# ----------------------------------------------------------------------
643
660
# Constructors
644
661
@@ -3668,9 +3685,9 @@ def _ixs(self, i: int, axis: AxisInt = 0) -> Series:
3668
3685
3669
3686
# if we are a copy, mark as such
3670
3687
copy = isinstance (new_mgr .array , np .ndarray ) and new_mgr .array .base is None
3671
- result = self ._constructor_sliced (new_mgr , name = self . index [ i ]). __finalize__ (
3672
- self
3673
- )
3688
+ result = self ._constructor_sliced_from_mgr (new_mgr , axes = new_mgr . axes )
3689
+ result . _name = self . index [ i ]
3690
+ result = result . __finalize__ ( self )
3674
3691
result ._set_is_copy (self , copy = copy )
3675
3692
return result
3676
3693
@@ -3723,7 +3740,7 @@ def _getitem_nocopy(self, key: list):
3723
3740
copy = False ,
3724
3741
only_slice = True ,
3725
3742
)
3726
- return self ._constructor (new_mgr )
3743
+ return self ._constructor_from_mgr (new_mgr , axes = new_mgr . axes )
3727
3744
3728
3745
def __getitem__ (self , key ):
3729
3746
check_dict_or_set_indexers (key )
@@ -4259,9 +4276,10 @@ def _box_col_values(self, values: SingleDataManager, loc: int) -> Series:
4259
4276
# Lookup in columns so that if e.g. a str datetime was passed
4260
4277
# we attach the Timestamp object as the name.
4261
4278
name = self .columns [loc ]
4262
- klass = self ._constructor_sliced
4263
4279
# We get index=self.index bc values is a SingleDataManager
4264
- return klass (values , name = name , fastpath = True ).__finalize__ (self )
4280
+ obj = self ._constructor_sliced_from_mgr (values , axes = values .axes )
4281
+ obj ._name = name
4282
+ return obj .__finalize__ (self )
4265
4283
4266
4284
# ----------------------------------------------------------------------
4267
4285
# Lookup Caching
@@ -4735,7 +4753,7 @@ def predicate(arr: ArrayLike) -> bool:
4735
4753
return True
4736
4754
4737
4755
mgr = self ._mgr ._get_data_subset (predicate ).copy (deep = None )
4738
- return type ( self ) (mgr ).__finalize__ (self )
4756
+ return self . _constructor_from_mgr (mgr , axes = mgr . axes ).__finalize__ (self )
4739
4757
4740
4758
def insert (
4741
4759
self ,
@@ -5547,7 +5565,7 @@ def shift(
5547
5565
fill_value = fill_value ,
5548
5566
allow_dups = True ,
5549
5567
)
5550
- res_df = self ._constructor (mgr )
5568
+ res_df = self ._constructor_from_mgr (mgr , axes = mgr . axes )
5551
5569
return res_df .__finalize__ (self , method = "shift" )
5552
5570
5553
5571
return super ().shift (
@@ -6075,7 +6093,8 @@ class max type
6075
6093
6076
6094
@doc (NDFrame .isna , klass = _shared_doc_kwargs ["klass" ])
6077
6095
def isna (self ) -> DataFrame :
6078
- result = self ._constructor (self ._mgr .isna (func = isna ))
6096
+ res_mgr = self ._mgr .isna (func = isna )
6097
+ result = self ._constructor_from_mgr (res_mgr , axes = res_mgr .axes )
6079
6098
return result .__finalize__ (self , method = "isna" )
6080
6099
6081
6100
@doc (NDFrame .isna , klass = _shared_doc_kwargs ["klass" ])
@@ -6787,7 +6806,7 @@ def sort_values(
6787
6806
self ._get_block_manager_axis (axis ), default_index (len (indexer ))
6788
6807
)
6789
6808
6790
- result = self ._constructor (new_data )
6809
+ result = self ._constructor_from_mgr (new_data , axes = new_data . axes )
6791
6810
if inplace :
6792
6811
return self ._update_inplace (result )
6793
6812
else :
@@ -7481,7 +7500,7 @@ def _dispatch_frame_op(
7481
7500
if not is_list_like (right ):
7482
7501
# i.e. scalar, faster than checking np.ndim(right) == 0
7483
7502
bm = self ._mgr .apply (array_op , right = right )
7484
- return self ._constructor (bm )
7503
+ return self ._constructor_from_mgr (bm , axes = bm . axes )
7485
7504
7486
7505
elif isinstance (right , DataFrame ):
7487
7506
assert self .index .equals (right .index )
@@ -7501,7 +7520,7 @@ def _dispatch_frame_op(
7501
7520
right ._mgr , # type: ignore[arg-type]
7502
7521
array_op ,
7503
7522
)
7504
- return self ._constructor (bm )
7523
+ return self ._constructor_from_mgr (bm , axes = bm . axes )
7505
7524
7506
7525
elif isinstance (right , Series ) and axis == 1 :
7507
7526
# axis=1 means we want to operate row-by-row
@@ -9480,7 +9499,8 @@ def diff(self, periods: int = 1, axis: Axis = 0) -> DataFrame:
9480
9499
axis = 0
9481
9500
9482
9501
new_data = self ._mgr .diff (n = periods )
9483
- return self ._constructor (new_data ).__finalize__ (self , "diff" )
9502
+ res_df = self ._constructor_from_mgr (new_data , axes = new_data .axes )
9503
+ return res_df .__finalize__ (self , "diff" )
9484
9504
9485
9505
# ----------------------------------------------------------------------
9486
9506
# Function application
@@ -10336,12 +10356,13 @@ def _series_round(ser: Series, decimals: int) -> Series:
10336
10356
# Dispatch to Block.round
10337
10357
# Argument "decimals" to "round" of "BaseBlockManager" has incompatible
10338
10358
# type "Union[int, integer[Any]]"; expected "int"
10339
- return self ._constructor (
10340
- self ._mgr .round (
10341
- decimals = decimals , # type: ignore[arg-type]
10342
- using_cow = using_copy_on_write (),
10343
- ),
10344
- ).__finalize__ (self , method = "round" )
10359
+ new_mgr = self ._mgr .round (
10360
+ decimals = decimals , # type: ignore[arg-type]
10361
+ using_cow = using_copy_on_write (),
10362
+ )
10363
+ return self ._constructor_from_mgr (new_mgr , axes = new_mgr .axes ).__finalize__ (
10364
+ self , method = "round"
10365
+ )
10345
10366
else :
10346
10367
raise TypeError ("decimals must be an integer, a dict-like or a Series" )
10347
10368
@@ -10893,7 +10914,7 @@ def _get_data() -> DataFrame:
10893
10914
# After possibly _get_data and transposing, we are now in the
10894
10915
# simple case where we can use BlockManager.reduce
10895
10916
res = df ._mgr .reduce (blk_func )
10896
- out = df ._constructor (res ).iloc [0 ]
10917
+ out = df ._constructor_from_mgr (res , axes = res . axes ).iloc [0 ]
10897
10918
if out_dtype is not None :
10898
10919
out = out .astype (out_dtype )
10899
10920
elif (df ._mgr .get_dtypes () == object ).any ():
@@ -11507,7 +11528,7 @@ def quantile(
11507
11528
res = data ._mgr .take (indexer [q_idx ], verify = False )
11508
11529
res .axes [1 ] = q
11509
11530
11510
- result = self ._constructor (res )
11531
+ result = self ._constructor_from_mgr (res , axes = res . axes )
11511
11532
return result .__finalize__ (self , method = "quantile" )
11512
11533
11513
11534
def to_timestamp (
@@ -11835,7 +11856,7 @@ def _to_dict_of_blocks(self, copy: bool = True):
11835
11856
mgr = mgr_to_mgr (mgr , "block" )
11836
11857
mgr = cast (BlockManager , mgr )
11837
11858
return {
11838
- k : self ._constructor ( v ).__finalize__ (self )
11859
+ k : self ._constructor_from_mgr ( v , axes = v . axes ).__finalize__ (self )
11839
11860
for k , v , in mgr .to_dict (copy = copy ).items ()
11840
11861
}
11841
11862
0 commit comments