Skip to content
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

DEPR: mad #46707

Merged
merged 4 commits into from
Apr 9, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ Other Deprecations
- Deprecated :attr:`Timedelta.freq` and :attr:`Timedelta.is_populated` (:issue:`46430`)
- Deprecated :attr:`Timedelta.delta` (:issue:`46476`)
- Deprecated the ``closed`` argument in :meth:`interval_range` in favor of ``inclusive`` argument; In a future version passing ``closed`` will raise (:issue:`40245`)
-
- Deprecated the methods :meth:`DataFrame.mad`, :meth:`Series.mad`, and the corresponding groupby methods (:issue:`11787`)

.. ---------------------------------------------------------------------------
.. _whatsnew_150.performance:
Expand Down
9 changes: 9 additions & 0 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10881,6 +10881,9 @@ def mad(
"""
{desc}

.. deprecated:: 1.5.0
mad is deprecated.

Parameters
----------
axis : {axis_descr}
Expand All @@ -10897,6 +10900,12 @@ def mad(
{see_also}\
{examples}
"""
msg = (
"The 'mad' method is deprecated "
"and will be removed in a future version. "
mroeschke marked this conversation as resolved.
Show resolved Hide resolved
)
warnings.warn(msg, FutureWarning, stacklevel=find_stack_level())

if not is_bool(skipna):
warnings.warn(
"Passing None for skipna is deprecated and will raise in a future"
Expand Down
78 changes: 53 additions & 25 deletions pandas/tests/frame/test_reductions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def assert_stat_op_calc(
skipna_alternative : function, default None
NaN-safe version of alternative
"""
warn = FutureWarning if opname == "mad" else None
f = getattr(frame, opname)

if check_dates:
Expand All @@ -88,8 +89,9 @@ def wrapper(x):
return alternative(x.values)

skipna_wrapper = tm._make_skipna_wrapper(alternative, skipna_alternative)
result0 = f(axis=0, skipna=False)
result1 = f(axis=1, skipna=False)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result0 = f(axis=0, skipna=False)
result1 = f(axis=1, skipna=False)
tm.assert_series_equal(
result0, frame.apply(wrapper), check_dtype=check_dtype, rtol=rtol, atol=atol
)
Expand All @@ -102,8 +104,9 @@ def wrapper(x):
else:
skipna_wrapper = alternative

result0 = f(axis=0)
result1 = f(axis=1)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result0 = f(axis=0)
result1 = f(axis=1)
tm.assert_series_equal(
result0,
frame.apply(skipna_wrapper),
Expand All @@ -125,14 +128,18 @@ def wrapper(x):
assert lcd_dtype == result1.dtype

# bad axis
with pytest.raises(ValueError, match="No axis named 2"):
f(axis=2)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
with pytest.raises(ValueError, match="No axis named 2"):
f(axis=2)

# all NA case
if has_skipna:
all_na = frame * np.NaN
r0 = getattr(all_na, opname)(axis=0)
r1 = getattr(all_na, opname)(axis=1)
with tm.assert_produces_warning(
warn, match="The 'mad' method is deprecated", raise_on_extra_warnings=False
):
r0 = getattr(all_na, opname)(axis=0)
r1 = getattr(all_na, opname)(axis=1)
if opname in ["sum", "prod"]:
unit = 1 if opname == "prod" else 0 # result for empty sum/prod
expected = Series(unit, index=r0.index, dtype=r0.dtype)
Expand Down Expand Up @@ -167,9 +174,13 @@ class TestDataFrameAnalytics:
],
)
def test_stat_op_api_float_string_frame(self, float_string_frame, axis, opname):
getattr(float_string_frame, opname)(axis=axis)
if opname not in ("nunique", "mad"):
getattr(float_string_frame, opname)(axis=axis, numeric_only=True)
warn = FutureWarning if opname == "mad" else None
with tm.assert_produces_warning(
warn, match="The 'mad' method is deprecated", raise_on_extra_warnings=False
):
getattr(float_string_frame, opname)(axis=axis)
if opname not in ("nunique", "mad"):
getattr(float_string_frame, opname)(axis=axis, numeric_only=True)

@pytest.mark.filterwarnings("ignore:Dropping of nuisance:FutureWarning")
@pytest.mark.parametrize("axis", [0, 1])
Expand Down Expand Up @@ -1424,7 +1435,9 @@ def test_frame_any_with_timedelta(self):
def test_reductions_deprecation_skipna_none(self, frame_or_series):
# GH#44580
obj = frame_or_series([1, 2, 3])
with tm.assert_produces_warning(FutureWarning, match="skipna"):
with tm.assert_produces_warning(
FutureWarning, match="skipna", raise_on_extra_warnings=False
):
obj.mad(skipna=None)

def test_reductions_deprecation_level_argument(
Expand All @@ -1445,7 +1458,7 @@ def test_reductions_skipna_none_raises(
pytest.mark.xfail(reason="Count does not accept skipna")
)
elif reduction_functions == "mad":
pytest.skip("Mad needs a deprecation cycle: GH 11787")
pytest.skip("Mad is deprecated: GH#11787")
obj = frame_or_series([1, 2, 3])
msg = 'For argument "skipna" expected type bool, received type NoneType.'
with pytest.raises(ValueError, match=msg):
Expand Down Expand Up @@ -1644,25 +1657,37 @@ def test_mad_nullable_integer(any_signed_int_ea_dtype):
df = DataFrame(np.random.randn(100, 4).astype(np.int64))
df2 = df.astype(any_signed_int_ea_dtype)

result = df2.mad()
expected = df.mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = df2.mad()
expected = df.mad()
tm.assert_series_equal(result, expected)

result = df2.mad(axis=1)
expected = df.mad(axis=1)
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = df2.mad(axis=1)
expected = df.mad(axis=1)
tm.assert_series_equal(result, expected)

# case with NAs present
df2.iloc[::2, 1] = pd.NA

result = df2.mad()
expected = df.mad()
expected[1] = df.iloc[1::2, 1].mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = df2.mad()
expected = df.mad()
expected[1] = df.iloc[1::2, 1].mad()
tm.assert_series_equal(result, expected)

result = df2.mad(axis=1)
expected = df.mad(axis=1)
expected[::2] = df.T.loc[[0, 2, 3], ::2].mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = df2.mad(axis=1)
expected = df.mad(axis=1)
expected[::2] = df.T.loc[[0, 2, 3], ::2].mad()
tm.assert_series_equal(result, expected)


Expand All @@ -1675,8 +1700,11 @@ def test_mad_nullable_integer_all_na(any_signed_int_ea_dtype):
# case with all-NA row/column
df2.iloc[:, 1] = pd.NA # FIXME(GH#44199): this doesn't operate in-place
df2.iloc[:, 1] = pd.array([pd.NA] * len(df2), dtype=any_signed_int_ea_dtype)
result = df2.mad()
expected = df.mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = df2.mad()
expected = df.mad()
expected[1] = pd.NA
expected = expected.astype("Float64")
tm.assert_series_equal(result, expected)
Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/groupby/aggregate/test_aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1325,11 +1325,13 @@ def test_groupby_aggregate_directory(reduction_func):
# GH#32793
if reduction_func in ["corrwith", "nth"]:
return None
warn = FutureWarning if reduction_func == "mad" else None

obj = DataFrame([[0, 1], [0, np.nan]])

result_reduced_series = obj.groupby(0).agg(reduction_func)
result_reduced_frame = obj.groupby(0).agg({1: reduction_func})
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result_reduced_series = obj.groupby(0).agg(reduction_func)
result_reduced_frame = obj.groupby(0).agg({1: reduction_func})

if reduction_func in ["size", "ngroup"]:
# names are different: None / 1
Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/groupby/test_allowlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def test_regression_allowlist_methods(raw_frame, op, level, axis, skipna, sort):
# GH6944
# GH 17537
# explicitly test the allowlist methods
warn = FutureWarning if op == "mad" else None

if axis == 0:
frame = raw_frame
Expand All @@ -186,7 +187,8 @@ def test_regression_allowlist_methods(raw_frame, op, level, axis, skipna, sort):

if op in AGG_FUNCTIONS_WITH_SKIPNA:
grouped = frame.groupby(level=level, axis=axis, sort=sort)
result = getattr(grouped, op)(skipna=skipna)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result = getattr(grouped, op)(skipna=skipna)
with tm.assert_produces_warning(FutureWarning):
expected = getattr(frame, op)(level=level, axis=axis, skipna=skipna)
if sort:
Expand Down
5 changes: 4 additions & 1 deletion pandas/tests/groupby/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,8 @@ def test_apply_with_timezones_aware():
def test_apply_is_unchanged_when_other_methods_are_called_first(reduction_func):
# GH #34656
# GH #34271
warn = FutureWarning if reduction_func == "mad" else None

df = DataFrame(
{
"a": [99, 99, 99, 88, 88, 88],
Expand All @@ -1068,7 +1070,8 @@ def test_apply_is_unchanged_when_other_methods_are_called_first(reduction_func):
# Check output when another method is called before .apply()
grp = df.groupby(by="a")
args = {"nth": [0], "corrwith": [df]}.get(reduction_func, [])
_ = getattr(grp, reduction_func)(*args)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
_ = getattr(grp, reduction_func)(*args)
result = grp.apply(sum)
tm.assert_frame_equal(result, expected)

Expand Down
16 changes: 12 additions & 4 deletions pandas/tests/groupby/test_categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,7 @@ def test_series_groupby_on_2_categoricals_unobserved(reduction_func, observed, r
reason="TODO: implemented SeriesGroupBy.corrwith. See GH 32293"
)
request.node.add_marker(mark)
warn = FutureWarning if reduction_func == "mad" else None

df = DataFrame(
{
Expand All @@ -1371,7 +1372,8 @@ def test_series_groupby_on_2_categoricals_unobserved(reduction_func, observed, r

series_groupby = df.groupby(["cat_1", "cat_2"], observed=observed)["value"]
agg = getattr(series_groupby, reduction_func)
result = agg(*args)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result = agg(*args)

assert len(result) == expected_length

Expand All @@ -1390,6 +1392,7 @@ def test_series_groupby_on_2_categoricals_unobserved_zeroes_or_nans(
reason="TODO: implemented SeriesGroupBy.corrwith. See GH 32293"
)
request.node.add_marker(mark)
warn = FutureWarning if reduction_func == "mad" else None

df = DataFrame(
{
Expand All @@ -1403,7 +1406,8 @@ def test_series_groupby_on_2_categoricals_unobserved_zeroes_or_nans(

series_groupby = df.groupby(["cat_1", "cat_2"], observed=False)["value"]
agg = getattr(series_groupby, reduction_func)
result = agg(*args)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
result = agg(*args)

zero_or_nan = _results_for_groupbys_with_missing_categories[reduction_func]

Expand All @@ -1426,6 +1430,7 @@ def test_dataframe_groupby_on_2_categoricals_when_observed_is_true(reduction_fun
# does not return the categories that are not in df when observed=True
if reduction_func == "ngroup":
pytest.skip("ngroup does not return the Categories on the index")
warn = FutureWarning if reduction_func == "mad" else None

df = DataFrame(
{
Expand All @@ -1439,7 +1444,8 @@ def test_dataframe_groupby_on_2_categoricals_when_observed_is_true(reduction_fun
df_grp = df.groupby(["cat_1", "cat_2"], observed=True)

args = {"nth": [0], "corrwith": [df]}.get(reduction_func, [])
res = getattr(df_grp, reduction_func)(*args)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
res = getattr(df_grp, reduction_func)(*args)

for cat in unobserved_cats:
assert cat not in res.index
Expand All @@ -1456,6 +1462,7 @@ def test_dataframe_groupby_on_2_categoricals_when_observed_is_false(

if reduction_func == "ngroup":
pytest.skip("ngroup does not return the Categories on the index")
warn = FutureWarning if reduction_func == "mad" else None

df = DataFrame(
{
Expand All @@ -1469,7 +1476,8 @@ def test_dataframe_groupby_on_2_categoricals_when_observed_is_false(
df_grp = df.groupby(["cat_1", "cat_2"], observed=observed)

args = {"nth": [0], "corrwith": [df]}.get(reduction_func, [])
res = getattr(df_grp, reduction_func)(*args)
with tm.assert_produces_warning(warn, match="The 'mad' method is deprecated"):
res = getattr(df_grp, reduction_func)(*args)

expected = _results_for_groupbys_with_missing_categories[reduction_func]

Expand Down
10 changes: 8 additions & 2 deletions pandas/tests/groupby/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,17 @@ def test_mad(self, gb, gni):
# mad
expected = DataFrame([[0], [np.nan]], columns=["B"], index=[1, 3])
expected.index.name = "A"
result = gb.mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = gb.mad()
tm.assert_frame_equal(result, expected)

expected = DataFrame([[1, 0.0], [3, np.nan]], columns=["A", "B"], index=[0, 1])
result = gni.mad()
with tm.assert_produces_warning(
FutureWarning, match="The 'mad' method is deprecated"
):
result = gni.mad()
tm.assert_frame_equal(result, expected)

def test_describe(self, df, gb, gni):
Expand Down