Skip to content

DEPR: method, limit, fill_axis keywords in align #51968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Deprecations
- Deprecated ``axis=1`` in :meth:`DataFrame.groupby` and in :class:`Grouper` constructor, do ``frame.T.groupby(...)`` instead (:issue:`51203`)
- Deprecated passing a :class:`DataFrame` to :meth:`DataFrame.from_records`, use :meth:`DataFrame.set_index` or :meth:`DataFrame.drop` instead (:issue:`51353`)
- Deprecated accepting slices in :meth:`DataFrame.take`, call ``obj[slicer]`` or pass a sequence of integers instead (:issue:`51539`)
- Deprecated 'method', 'limit', and 'fill_axis' keywords in :meth:`DataFrame.align` and :meth:`Series.align`, explicitly call ``fillna`` on the alignment results instead (:issue:`51856`)
-

.. ---------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -5014,9 +5014,9 @@ def align(
level: Level = None,
copy: bool | None = None,
fill_value=None,
method: FillnaOptions | None = None,
limit: int | None = None,
fill_axis: Axis = 0,
method: FillnaOptions | None | lib.NoDefault = lib.no_default,
limit: int | None | lib.NoDefault = lib.no_default,
fill_axis: Axis | lib.NoDefault = lib.no_default,
broadcast_axis: Axis | None = None,
) -> tuple[Self, NDFrameT]:
return super().align(
Expand Down
35 changes: 31 additions & 4 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -9318,9 +9318,9 @@ def align(
level: Level = None,
copy: bool_t | None = None,
fill_value: Hashable = None,
method: FillnaOptions | None = None,
limit: int | None = None,
fill_axis: Axis = 0,
method: FillnaOptions | None | lib.NoDefault = lib.no_default,
limit: int | None | lib.NoDefault = lib.no_default,
fill_axis: Axis | lib.NoDefault = lib.no_default,
broadcast_axis: Axis | None = None,
) -> tuple[Self, NDFrameT]:
"""
Expand Down Expand Up @@ -9349,15 +9349,23 @@ def align(
- pad / ffill: propagate last valid observation forward to next valid.
- backfill / bfill: use NEXT valid observation to fill gap.

.. deprecated:: 2.1

limit : int, default None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change the defaults to lib.no_default? (for all keywords)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess thatd be harmless, OK

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call here, we had a few places where we explicitly passed method=None that werent caught in the previous version.

want to weigh in on broadcast_axis in #51856?

If method is specified, this is the maximum number of consecutive
NaN values to forward/backward fill. In other words, if there is
a gap with more than this number of consecutive NaNs, it will only
be partially filled. If method is not specified, this is the
maximum number of entries along the entire axis where NaNs will be
filled. Must be greater than 0 if not None.

.. deprecated:: 2.1

fill_axis : {axes_single_arg}, default 0
Filling axis, method and limit.

.. deprecated:: 2.1

broadcast_axis : {axes_single_arg}, default None
Broadcast values along this axis, if aligning two objects of
different dimensions.
Expand Down Expand Up @@ -9432,7 +9440,26 @@ def align(
3 60.0 70.0 80.0 90.0 NaN
4 600.0 700.0 800.0 900.0 NaN
"""

if (
method is not lib.no_default
or limit is not lib.no_default
or fill_axis is not lib.no_default
):
# GH#51856
warnings.warn(
"The 'method', 'limit', and 'fill_axis' keywords in "
f"{type(self).__name__}.align are deprecated and will be removed "
"in a future version. Call fillna directly on the returned objects "
"instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
if fill_axis is lib.no_default:
fill_axis = 0
if method is lib.no_default:
method = None
if limit is lib.no_default:
limit = None
method = clean_fill_method(method)

if broadcast_axis == 1 and self.ndim != other.ndim:
Expand Down
6 changes: 3 additions & 3 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4596,9 +4596,9 @@ def align(
level: Level = None,
copy: bool | None = None,
fill_value: Hashable = None,
method: FillnaOptions | None = None,
limit: int | None = None,
fill_axis: Axis = 0,
method: FillnaOptions | None | lib.NoDefault = lib.no_default,
limit: int | None | lib.NoDefault = lib.no_default,
fill_axis: Axis | lib.NoDefault = lib.no_default,
broadcast_axis: Axis | None = None,
) -> tuple[Self, NDFrameT]:
return super().align(
Expand Down
69 changes: 55 additions & 14 deletions pandas/tests/frame/methods/test_align.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,32 @@ def test_align_float(self, float_frame, using_copy_on_write):
af, bf = float_frame.align(other, join="inner", axis=1)
tm.assert_index_equal(bf.columns, other.columns)

af, bf = float_frame.align(other, join="inner", axis=1, method="pad")
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = float_frame.align(other, join="inner", axis=1, method="pad")
tm.assert_index_equal(bf.columns, other.columns)

af, bf = float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=None
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=None
)
tm.assert_index_equal(bf.index, Index([]))

af, bf = float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
)
tm.assert_index_equal(bf.index, Index([]))

# Try to align DataFrame to Series along bad axis
Expand Down Expand Up @@ -134,30 +149,50 @@ def test_align_int(self, int_frame):
# test other non-float types
other = DataFrame(index=range(5), columns=["A", "B", "C"])

af, bf = int_frame.align(other, join="inner", axis=1, method="pad")
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = int_frame.align(other, join="inner", axis=1, method="pad")
tm.assert_index_equal(bf.columns, other.columns)

def test_align_mixed_type(self, float_string_frame):
af, bf = float_string_frame.align(
float_string_frame, join="inner", axis=1, method="pad"
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = float_string_frame.align(
float_string_frame, join="inner", axis=1, method="pad"
)
tm.assert_index_equal(bf.columns, float_string_frame.columns)

def test_align_mixed_float(self, mixed_float_frame):
# mixed floats/ints
other = DataFrame(index=range(5), columns=["A", "B", "C"])

af, bf = mixed_float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = mixed_float_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
)
tm.assert_index_equal(bf.index, Index([]))

def test_align_mixed_int(self, mixed_int_frame):
other = DataFrame(index=range(5), columns=["A", "B", "C"])

af, bf = mixed_int_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
af, bf = mixed_int_frame.align(
other.iloc[:, 0], join="inner", axis=1, method=None, fill_value=0
)
tm.assert_index_equal(bf.index, Index([]))

@pytest.mark.parametrize(
Expand Down Expand Up @@ -348,10 +383,16 @@ def test_missing_axis_specification_exception(self):
df.align(series)

def _check_align(self, a, b, axis, fill_axis, how, method, limit=None):
aa, ab = a.align(
b, axis=axis, join=how, method=method, limit=limit, fill_axis=fill_axis
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in DataFrame.align "
"are deprecated"
)

with tm.assert_produces_warning(FutureWarning, match=msg):
aa, ab = a.align(
b, axis=axis, join=how, method=method, limit=limit, fill_axis=fill_axis
)

join_index, join_columns = None, None

ea, eb = a, b
Expand Down
14 changes: 12 additions & 2 deletions pandas/tests/series/methods/test_align.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ def test_align_fill_method(
a = datetime_series[slice(*first_slice)]
b = datetime_series[slice(*second_slice)]

aa, ab = a.align(b, join=join_type, method=method, limit=limit)
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in Series.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
aa, ab = a.align(b, join=join_type, method=method, limit=limit)

join_index = a.index.join(b.index, how=join_type)
ea = a.reindex(join_index)
Expand Down Expand Up @@ -173,7 +178,12 @@ def test_align_with_dataframe_method(method):
ser = Series(range(3), index=range(3))
df = pd.DataFrame(0.0, index=range(3), columns=range(3))

result_ser, result_df = ser.align(df, method=method)
msg = (
"The 'method', 'limit', and 'fill_axis' keywords in Series.align "
"are deprecated"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
result_ser, result_df = ser.align(df, method=method)
tm.assert_series_equal(result_ser, ser)
tm.assert_frame_equal(result_df, df)

Expand Down