diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 1b2aa1d053240..f98a08810c3ff 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -735,7 +735,7 @@ def apply(self) -> DataFrame | Series: with np.errstate(all="ignore"): results = self.obj._mgr.apply("apply", func=self.func) # _constructor will retain self.index and self.columns - return self.obj._constructor(data=results) + return self.obj._constructor_from_mgr(results, axes=results.axes) # broadcasting if self.result_type == "broadcast": diff --git a/pandas/core/arraylike.py b/pandas/core/arraylike.py index 1d10d797866f4..62f6737d86d51 100644 --- a/pandas/core/arraylike.py +++ b/pandas/core/arraylike.py @@ -349,7 +349,7 @@ def _reconstruct(result): return result if isinstance(result, BlockManager): # we went through BlockManager.apply e.g. np.sqrt - result = self._constructor(result, **reconstruct_kwargs, copy=False) + result = self._constructor_from_mgr(result, axes=result.axes) else: # we converted an array, lost our axes result = self._constructor( diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 4088736dd4150..b4f72a4b7894b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -637,8 +637,25 @@ class DataFrame(NDFrame, OpsMixin): def _constructor(self) -> Callable[..., DataFrame]: return DataFrame + def _constructor_from_mgr(self, mgr, axes): + if self._constructor is DataFrame: + # we are pandas.DataFrame (or a subclass that doesn't override _constructor) + return self._from_mgr(mgr, axes=axes) + else: + assert axes is mgr.axes + return self._constructor(mgr) + _constructor_sliced: Callable[..., Series] = Series + def _sliced_from_mgr(self, mgr, axes) -> Series: + return Series._from_mgr(mgr, axes) + + def _constructor_sliced_from_mgr(self, mgr, axes): + if self._constructor_sliced is Series: + return self._sliced_from_mgr(mgr, axes) + assert axes is mgr.axes + return self._constructor_sliced(mgr) + # ---------------------------------------------------------------------- # Constructors @@ -3668,9 +3685,9 @@ def _ixs(self, i: int, axis: AxisInt = 0) -> Series: # if we are a copy, mark as such copy = isinstance(new_mgr.array, np.ndarray) and new_mgr.array.base is None - result = self._constructor_sliced(new_mgr, name=self.index[i]).__finalize__( - self - ) + result = self._constructor_sliced_from_mgr(new_mgr, axes=new_mgr.axes) + result._name = self.index[i] + result = result.__finalize__(self) result._set_is_copy(self, copy=copy) return result @@ -3723,7 +3740,7 @@ def _getitem_nocopy(self, key: list): copy=False, only_slice=True, ) - return self._constructor(new_mgr) + return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) def __getitem__(self, key): check_dict_or_set_indexers(key) @@ -4259,9 +4276,10 @@ def _box_col_values(self, values: SingleDataManager, loc: int) -> Series: # Lookup in columns so that if e.g. a str datetime was passed # we attach the Timestamp object as the name. name = self.columns[loc] - klass = self._constructor_sliced # We get index=self.index bc values is a SingleDataManager - return klass(values, name=name, fastpath=True).__finalize__(self) + obj = self._constructor_sliced_from_mgr(values, axes=values.axes) + obj._name = name + return obj.__finalize__(self) # ---------------------------------------------------------------------- # Lookup Caching @@ -4735,7 +4753,7 @@ def predicate(arr: ArrayLike) -> bool: return True mgr = self._mgr._get_data_subset(predicate).copy(deep=None) - return type(self)(mgr).__finalize__(self) + return self._constructor_from_mgr(mgr, axes=mgr.axes).__finalize__(self) def insert( self, @@ -5547,7 +5565,7 @@ def shift( fill_value=fill_value, allow_dups=True, ) - res_df = self._constructor(mgr) + res_df = self._constructor_from_mgr(mgr, axes=mgr.axes) return res_df.__finalize__(self, method="shift") return super().shift( @@ -6075,7 +6093,8 @@ class max type @doc(NDFrame.isna, klass=_shared_doc_kwargs["klass"]) def isna(self) -> DataFrame: - result = self._constructor(self._mgr.isna(func=isna)) + res_mgr = self._mgr.isna(func=isna) + result = self._constructor_from_mgr(res_mgr, axes=res_mgr.axes) return result.__finalize__(self, method="isna") @doc(NDFrame.isna, klass=_shared_doc_kwargs["klass"]) @@ -6787,7 +6806,7 @@ def sort_values( self._get_block_manager_axis(axis), default_index(len(indexer)) ) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) if inplace: return self._update_inplace(result) else: @@ -7481,7 +7500,7 @@ def _dispatch_frame_op( if not is_list_like(right): # i.e. scalar, faster than checking np.ndim(right) == 0 bm = self._mgr.apply(array_op, right=right) - return self._constructor(bm) + return self._constructor_from_mgr(bm, axes=bm.axes) elif isinstance(right, DataFrame): assert self.index.equals(right.index) @@ -7501,7 +7520,7 @@ def _dispatch_frame_op( right._mgr, # type: ignore[arg-type] array_op, ) - return self._constructor(bm) + return self._constructor_from_mgr(bm, axes=bm.axes) elif isinstance(right, Series) and axis == 1: # axis=1 means we want to operate row-by-row @@ -9480,7 +9499,8 @@ def diff(self, periods: int = 1, axis: Axis = 0) -> DataFrame: axis = 0 new_data = self._mgr.diff(n=periods) - return self._constructor(new_data).__finalize__(self, "diff") + res_df = self._constructor_from_mgr(new_data, axes=new_data.axes) + return res_df.__finalize__(self, "diff") # ---------------------------------------------------------------------- # Function application @@ -10336,12 +10356,13 @@ def _series_round(ser: Series, decimals: int) -> Series: # Dispatch to Block.round # Argument "decimals" to "round" of "BaseBlockManager" has incompatible # type "Union[int, integer[Any]]"; expected "int" - return self._constructor( - self._mgr.round( - decimals=decimals, # type: ignore[arg-type] - using_cow=using_copy_on_write(), - ), - ).__finalize__(self, method="round") + new_mgr = self._mgr.round( + decimals=decimals, # type: ignore[arg-type] + using_cow=using_copy_on_write(), + ) + return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__( + self, method="round" + ) else: raise TypeError("decimals must be an integer, a dict-like or a Series") @@ -10893,7 +10914,7 @@ def _get_data() -> DataFrame: # After possibly _get_data and transposing, we are now in the # simple case where we can use BlockManager.reduce res = df._mgr.reduce(blk_func) - out = df._constructor(res).iloc[0] + out = df._constructor_from_mgr(res, axes=res.axes).iloc[0] if out_dtype is not None: out = out.astype(out_dtype) elif (df._mgr.get_dtypes() == object).any(): @@ -11507,7 +11528,7 @@ def quantile( res = data._mgr.take(indexer[q_idx], verify=False) res.axes[1] = q - result = self._constructor(res) + result = self._constructor_from_mgr(res, axes=res.axes) return result.__finalize__(self, method="quantile") def to_timestamp( @@ -11835,7 +11856,7 @@ def _to_dict_of_blocks(self, copy: bool = True): mgr = mgr_to_mgr(mgr, "block") mgr = cast(BlockManager, mgr) return { - k: self._constructor(v).__finalize__(self) + k: self._constructor_from_mgr(v, axes=v.axes).__finalize__(self) for k, v, in mgr.to_dict(copy=copy).items() } diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0be840f9a4ef1..8cff84945cbf0 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -321,6 +321,26 @@ def _as_manager(self, typ: str, copy: bool_t = True) -> Self: # fastpath of passing a manager doesn't check the option/manager class return self._constructor(new_mgr).__finalize__(self) + @classmethod + def _from_mgr(cls, mgr: Manager, axes: list[Index]) -> Self: + """ + Construct a new object of this type from a Manager object and axes. + + Parameters + ---------- + mgr : Manager + Must have the same ndim as cls. + axes : list[Index] + + Notes + ----- + The axes must match mgr.axes, but are required for future-proofing + in the event that axes are refactored out of the Manager objects. + """ + obj = cls.__new__(cls) + NDFrame.__init__(obj, mgr) + return obj + # ---------------------------------------------------------------------- # attrs and flags @@ -1444,7 +1464,7 @@ def blk_func(values: ArrayLike): return operator.neg(values) # type: ignore[arg-type] new_data = self._mgr.apply(blk_func) - res = self._constructor(new_data) + res = self._constructor_from_mgr(new_data, axes=new_data.axes) return res.__finalize__(self, method="__neg__") @final @@ -1459,7 +1479,7 @@ def blk_func(values: ArrayLike): return operator.pos(values) # type: ignore[arg-type] new_data = self._mgr.apply(blk_func) - res = self._constructor(new_data) + res = self._constructor_from_mgr(new_data, axes=new_data.axes) return res.__finalize__(self, method="__pos__") @final @@ -1469,7 +1489,8 @@ def __invert__(self) -> Self: return self.copy(deep=False) new_data = self._mgr.apply(operator.invert) - return self._constructor(new_data).__finalize__(self, method="__invert__") + res = self._constructor_from_mgr(new_data, axes=new_data.axes) + return res.__finalize__(self, method="__invert__") @final def __nonzero__(self) -> NoReturn: @@ -1607,7 +1628,9 @@ def abs(self) -> Self: 3 7 40 -50 """ res_mgr = self._mgr.apply(np.abs) - return self._constructor(res_mgr).__finalize__(self, name="abs") + return self._constructor_from_mgr(res_mgr, axes=res_mgr.axes).__finalize__( + self, name="abs" + ) @final def __abs__(self) -> Self: @@ -4019,7 +4042,9 @@ class max_speed axis=self._get_block_manager_axis(axis), verify=True, ) - return self._constructor(new_data).__finalize__(self, method="take") + return self._constructor_from_mgr(new_data, axes=new_data.axes).__finalize__( + self, method="take" + ) @final def _take_with_is_copy(self, indices, axis: Axis = 0) -> Self: @@ -4202,9 +4227,9 @@ class animal locomotion new_mgr = self._mgr.fast_xs(loc) - result = self._constructor_sliced( - new_mgr, name=self.index[loc] - ).__finalize__(self) + result = self._constructor_sliced_from_mgr(new_mgr, axes=new_mgr.axes) + result._name = self.index[loc] + result = result.__finalize__(self) elif is_scalar(loc): result = self.iloc[:, slice(loc, loc + 1)] elif axis == 1: @@ -4248,7 +4273,8 @@ def _slice(self, slobj: slice, axis: AxisInt = 0) -> Self: """ assert isinstance(slobj, slice), type(slobj) axis = self._get_block_manager_axis(axis) - result = self._constructor(self._mgr.get_slice(slobj, axis=axis)) + new_mgr = self._mgr.get_slice(slobj, axis=axis) + result = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) result = result.__finalize__(self) # this could be a view @@ -4743,7 +4769,7 @@ def _drop_axis( copy=None, only_slice=only_slice, ) - result = self._constructor(new_mgr) + result = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) if self.ndim == 1: result._name = self.name @@ -5202,7 +5228,7 @@ def sort_index( axis = 1 if isinstance(self, ABCDataFrame) else 0 new_data.set_axis(axis, default_index(len(indexer))) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) if inplace: return self._update_inplace(result) @@ -5563,7 +5589,9 @@ def _reindex_with_indexers( elif using_copy_on_write() and new_data is self._mgr: new_data = new_data.copy(deep=False) - return self._constructor(new_data).__finalize__(self) + return self._constructor_from_mgr(new_data, axes=new_data.axes).__finalize__( + self + ) def filter( self, @@ -6233,7 +6261,9 @@ def _consolidate(self): """ f = lambda: self._mgr.consolidate() cons_data = self._protect_consolidate(f) - return self._constructor(cons_data).__finalize__(self) + return self._constructor_from_mgr(cons_data, axes=cons_data.axes).__finalize__( + self + ) @property def _is_mixed_type(self) -> bool_t: @@ -6249,11 +6279,13 @@ def _is_mixed_type(self) -> bool_t: @final def _get_numeric_data(self) -> Self: - return self._constructor(self._mgr.get_numeric_data()).__finalize__(self) + new_mgr = self._mgr.get_numeric_data() + return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) @final def _get_bool_data(self): - return self._constructor(self._mgr.get_bool_data()).__finalize__(self) + new_mgr = self._mgr.get_bool_data() + return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) # ---------------------------------------------------------------------- # Internal Interface Methods @@ -6463,7 +6495,8 @@ def astype( else: # else, only a single dtype is given new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors) - return self._constructor(new_data).__finalize__(self, method="astype") + res = self._constructor_from_mgr(new_data, axes=new_data.axes) + return res.__finalize__(self, method="astype") # GH 33113: handle empty frame or series if not results: @@ -6592,7 +6625,9 @@ def copy(self, deep: bool_t | None = True) -> Self: """ data = self._mgr.copy(deep=deep) self._clear_item_cache() - return self._constructor(data).__finalize__(self, method="copy") + return self._constructor_from_mgr(data, axes=data.axes).__finalize__( + self, method="copy" + ) @final def __copy__(self, deep: bool_t = True) -> Self: @@ -6654,7 +6689,8 @@ def infer_objects(self, copy: bool_t | None = None) -> Self: dtype: object """ new_mgr = self._mgr.convert(copy=copy) - return self._constructor(new_mgr).__finalize__(self, method="infer_objects") + res = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) + return res.__finalize__(self, method="infer_objects") @final def convert_dtypes( @@ -7177,11 +7213,7 @@ def fillna( elif not is_list_like(value): if axis == 1: result = self.T.fillna(value=value, limit=limit).T - - # error: Incompatible types in assignment (expression - # has type "Self", variable has type "Union[ArrayManager, - # SingleArrayManager, BlockManager, SingleBlockManager]") - new_data = result # type: ignore[assignment] + new_data = result._mgr else: new_data = self._mgr.fillna( value=value, limit=limit, inplace=inplace, downcast=downcast @@ -7191,7 +7223,7 @@ def fillna( else: raise ValueError(f"invalid fill value with a {type(value)}") - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) if inplace: return self._update_inplace(result) else: @@ -7712,7 +7744,7 @@ def replace( f'Invalid "to_replace" type: {repr(type(to_replace).__name__)}' ) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) if inplace: return self._update_inplace(result) else: @@ -7988,7 +8020,7 @@ def interpolate( **kwargs, ) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) if should_transpose: result = result.T if inplace: @@ -9979,9 +10011,8 @@ def _align_series( elif lidx is None or join_index is None: left = self.copy(deep=copy) else: - left = self._constructor( - self._mgr.reindex_indexer(join_index, lidx, axis=1, copy=copy) - ) + new_mgr = self._mgr.reindex_indexer(join_index, lidx, axis=1, copy=copy) + left = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) right = other._reindex_indexer(join_index, ridx, copy) @@ -10002,7 +10033,7 @@ def _align_series( if copy and fdata is self._mgr: fdata = fdata.copy() - left = self._constructor(fdata) + left = self._constructor_from_mgr(fdata, axes=fdata.axes) if ridx is None: right = other.copy(deep=copy) @@ -10154,7 +10185,7 @@ def _where( # reconstruct the block manager new_data = self._mgr.putmask(mask=cond, new=other, align=align) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) return self._update_inplace(result) else: @@ -10163,7 +10194,7 @@ def _where( cond=cond, align=align, ) - result = self._constructor(new_data) + result = self._constructor_from_mgr(new_data, axes=new_data.axes) return result.__finalize__(self) @overload @@ -10541,7 +10572,9 @@ def shift( new_data = self._mgr.shift( periods=periods, axis=axis, fill_value=fill_value ) - return self._constructor(new_data).__finalize__(self, method="shift") + return self._constructor_from_mgr( + new_data, axes=new_data.axes + ).__finalize__(self, method="shift") # when freq is given, index is shifted, data is not index = self._get_axis(axis) @@ -11529,7 +11562,9 @@ def block_accum_func(blk_values): result = self._mgr.apply(block_accum_func) - return self._constructor(result).__finalize__(self, method=name) + return self._constructor_from_mgr(result, axes=result.axes).__finalize__( + self, method=name + ) def cummax(self, axis: Axis | None = None, skipna: bool_t = True, *args, **kwargs): return self._accum_func( diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 43854c5849481..6c8e9c3fe9a75 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -147,7 +147,9 @@ class NamedAgg(NamedTuple): class SeriesGroupBy(GroupBy[Series]): def _wrap_agged_manager(self, mgr: Manager) -> Series: - return self.obj._constructor(mgr, name=self.obj.name) + out = self.obj._constructor_from_mgr(mgr, axes=mgr.axes) + out._name = self.obj.name + return out def _get_data_to_aggregate( self, *, numeric_only: bool = False, name: str | None = None @@ -1682,7 +1684,7 @@ def arr_func(bvalues: ArrayLike) -> ArrayLike: res_mgr = mgr.grouped_reduce(arr_func) res_mgr.set_axis(1, mgr.axes[1]) - res_df = self.obj._constructor(res_mgr) + res_df = self.obj._constructor_from_mgr(res_mgr, axes=res_mgr.axes) res_df = self._maybe_transpose_result(res_df) return res_df @@ -1993,7 +1995,7 @@ def _get_data_to_aggregate( return mgr def _wrap_agged_manager(self, mgr: Manager2D) -> DataFrame: - return self.obj._constructor(mgr) + return self.obj._constructor_from_mgr(mgr, axes=mgr.axes) def _apply_to_column_groupbys(self, func) -> DataFrame: from pandas.core.reshape.concat import concat diff --git a/pandas/core/groupby/ops.py b/pandas/core/groupby/ops.py index 1cf27f37e469e..f0e4484f69f8d 100644 --- a/pandas/core/groupby/ops.py +++ b/pandas/core/groupby/ops.py @@ -1157,7 +1157,8 @@ class SeriesSplitter(DataSplitter): def _chop(self, sdata: Series, slice_obj: slice) -> Series: # fastpath equivalent to `sdata.iloc[slice_obj]` mgr = sdata._mgr.get_slice(slice_obj) - ser = sdata._constructor(mgr, name=sdata.name, fastpath=True) + ser = sdata._constructor_from_mgr(mgr, axes=mgr.axes) + ser._name = sdata.name return ser.__finalize__(sdata, method="groupby") @@ -1169,7 +1170,7 @@ def _chop(self, sdata: DataFrame, slice_obj: slice) -> DataFrame: # else: # return sdata.iloc[:, slice_obj] mgr = sdata._mgr.get_slice(slice_obj, axis=1 - self.axis) - df = sdata._constructor(mgr) + df = sdata._constructor_from_mgr(mgr, axes=mgr.axes) return df.__finalize__(sdata, method="groupby") diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 3fc0c47dd175e..8d3ff10ba91b3 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -2129,9 +2129,7 @@ def _take_new_index( if axis == 1: raise NotImplementedError("axis 1 is not supported") new_mgr = obj._mgr.reindex_indexer(new_axis=new_index, indexer=indexer, axis=1) - # error: Incompatible return value type - # (got "DataFrame", expected "NDFrameT") - return obj._constructor(new_mgr) # type: ignore[return-value] + return obj._constructor_from_mgr(new_mgr, axes=new_mgr.axes) else: raise ValueError("'obj' should be either a Series or a DataFrame") diff --git a/pandas/core/reshape/concat.py b/pandas/core/reshape/concat.py index 23fd93aca4258..4994ed347629e 100644 --- a/pandas/core/reshape/concat.py +++ b/pandas/core/reshape/concat.py @@ -681,8 +681,8 @@ def get_result(self): if not self.copy and not using_copy_on_write(): new_data._consolidate_inplace() - cons = sample._constructor - return cons(new_data).__finalize__(self, method="concat") + out = sample._constructor_from_mgr(new_data, axes=new_data.axes) + return out.__finalize__(self, method="concat") def _get_result_dim(self) -> int: if self._is_series and self.bm_axis == 1: diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index d406145e62ad7..26e4bea0e1690 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -786,7 +786,7 @@ def _reindex_and_concat( allow_dups=True, use_na_proxy=True, ) - left = left._constructor(lmgr) + left = left._constructor_from_mgr(lmgr, axes=lmgr.axes) left.index = join_index if right_indexer is not None and not is_range_indexer( @@ -801,7 +801,7 @@ def _reindex_and_concat( allow_dups=True, use_na_proxy=True, ) - right = right._constructor(rmgr) + right = right._constructor_from_mgr(rmgr, axes=rmgr.axes) right.index = join_index from pandas import concat diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py index 6b452f7cdaecf..5deaa41e2f63c 100644 --- a/pandas/core/reshape/reshape.py +++ b/pandas/core/reshape/reshape.py @@ -528,7 +528,7 @@ def _unstack_frame( if not obj._can_fast_transpose: mgr = obj._mgr.unstack(unstacker, fill_value=fill_value) - return obj._constructor(mgr) + return obj._constructor_from_mgr(mgr, axes=mgr.axes) else: return unstacker.get_result( obj._values, value_columns=obj.columns, fill_value=fill_value diff --git a/pandas/core/series.py b/pandas/core/series.py index 40c19a57466fe..798c19db7079d 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -574,6 +574,14 @@ def _init_dict( def _constructor(self) -> Callable[..., Series]: return Series + def _constructor_from_mgr(self, mgr, axes): + if self._constructor is Series: + # we are pandas.Series (or a subclass that doesn't override _constructor) + return self._from_mgr(mgr, axes=axes) + else: + assert axes is mgr.axes + return self._constructor(mgr) + @property def _constructor_expanddim(self) -> Callable[..., DataFrame]: """ @@ -584,6 +592,23 @@ def _constructor_expanddim(self) -> Callable[..., DataFrame]: return DataFrame + def _expanddim_from_mgr(self, mgr, axes) -> DataFrame: + # https://github.com/pandas-dev/pandas/pull/52132#issuecomment-1481491828 + # This is a short-term implementation that will be replaced + # with self._constructor_expanddim._constructor_from_mgr(...) + # once downstream packages (geopandas) have had a chance to implement + # their own overrides. + # error: "Callable[..., DataFrame]" has no attribute "_from_mgr" [attr-defined] + return self._constructor_expanddim._from_mgr( # type: ignore[attr-defined] + mgr, axes=mgr.axes + ) + + def _constructor_expanddim_from_mgr(self, mgr, axes): + if self._constructor is Series: + return self._expanddim_from_mgr(mgr, axes) + assert axes is mgr.axes + return self._constructor_expanddim(mgr) + # types @property def _can_hold_na(self) -> bool: @@ -1083,7 +1108,7 @@ def _get_values_tuple(self, key: tuple): def _get_rows_with_mask(self, indexer: npt.NDArray[np.bool_]) -> Series: new_mgr = self._mgr.get_rows_with_mask(indexer) - return self._constructor(new_mgr, fastpath=True).__finalize__(self) + return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) def _get_value(self, label, takeable: bool = False): """ @@ -1955,7 +1980,7 @@ def to_frame(self, name: Hashable = lib.no_default) -> DataFrame: columns = Index([name]) mgr = self._mgr.to_2d_mgr(columns) - df = self._constructor_expanddim(mgr) + df = self._constructor_expanddim_from_mgr(mgr, axes=mgr.axes) return df.__finalize__(self, method="to_frame") def _set_name(