Skip to content

Commit

Permalink
DEPR: Silent dropping of nuisance columns in transform_dict_like (#43743
Browse files Browse the repository at this point in the history
)
  • Loading branch information
rhshadrach committed Sep 26, 2021
1 parent befbc47 commit 8276a56
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 20 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ Other Deprecations
- Deprecated the ``squeeze`` argument to :meth:`read_csv`, :meth:`read_table`, and :meth:`read_excel`. Users should squeeze the DataFrame afterwards with ``.squeeze("columns")`` instead. (:issue:`43242`)
- Deprecated the ``index`` argument to :class:`SparseArray` construction (:issue:`23089`)
- Deprecated :meth:`.Rolling.validate`, :meth:`.Expanding.validate`, and :meth:`.ExponentialMovingWindow.validate` (:issue:`43665`)
- Deprecated silent dropping of columns that raised a ``TypeError`` in :class:`Series.transform` and :class:`DataFrame.transform` when used with a dictionary (:issue:`43740`)

.. ---------------------------------------------------------------------------
Expand Down
13 changes: 7 additions & 6 deletions pandas/core/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
FrameOrSeries,
)
from pandas.util._decorators import cache_readonly
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.cast import is_nested_object
from pandas.core.dtypes.common import (
Expand Down Expand Up @@ -271,21 +272,21 @@ def transform_dict_like(self, func):
"No transform functions were provided",
}:
raise err
elif not isinstance(err, TypeError):
all_type_errors = False
else:
if not isinstance(err, TypeError):
all_type_errors = False
failed_names.append(name)
# combine results
if not results:
klass = TypeError if all_type_errors else ValueError
raise klass("Transform function failed")
if len(failed_names) > 0:
warnings.warn(
f"{failed_names} did not transform successfully and did not raise "
f"a TypeError. If any error is raised except for TypeError, "
f"this will raise in a future version of pandas. "
f"{failed_names} did not transform successfully. If any error is "
f"raised, this will raise in a future version of pandas. "
f"Drop these columns/ops to avoid this warning.",
FutureWarning,
stacklevel=4,
stacklevel=find_stack_level(),
)
return concat(results, axis=1)

Expand Down
21 changes: 14 additions & 7 deletions pandas/tests/apply/test_frame_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,33 +160,40 @@ def test_transform_bad_dtype(op, frame_or_series, request):
@pytest.mark.parametrize("op", frame_kernels_raise)
def test_transform_partial_failure_typeerror(op):
# GH 35964

if op == "rank":
pytest.skip("GH 40418: rank does not raise a TypeError")

# Using object makes most transform kernels fail
df = DataFrame({"A": 3 * [object], "B": [1, 2, 3]})

expected = df[["B"]].transform([op])
result = df.transform([op])
match = r"\['A'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = df.transform([op])
tm.assert_equal(result, expected)

expected = df[["B"]].transform({"B": op})
result = df.transform({"A": op, "B": op})
match = r"\['A'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = df.transform({"A": op, "B": op})
tm.assert_equal(result, expected)

expected = df[["B"]].transform({"B": [op]})
result = df.transform({"A": [op], "B": [op]})
match = r"\['A'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = df.transform({"A": [op], "B": [op]})
tm.assert_equal(result, expected)

expected = df.transform({"A": ["shift"], "B": [op]})
result = df.transform({"A": [op, "shift"], "B": [op]})
match = rf"\['{op}'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = df.transform({"A": [op, "shift"], "B": [op]})
tm.assert_equal(result, expected)


def test_transform_partial_failure_valueerror():
# GH 40211
match = ".*did not transform successfully and did not raise a TypeError"
match = ".*did not transform successfully"

def op(x):
if np.sum(np.sum(x)) < 10:
Expand All @@ -211,7 +218,7 @@ def op(x):
tm.assert_equal(result, expected)

expected = df.transform({"A": ["shift"], "B": [op]})
with tm.assert_produces_warning(FutureWarning, match=match, check_stacklevel=False):
with tm.assert_produces_warning(FutureWarning, match=match):
result = df.transform({"A": [op, "shift"], "B": [op]})
tm.assert_equal(result, expected)

Expand Down
24 changes: 17 additions & 7 deletions pandas/tests/apply/test_series_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,25 +291,35 @@ def test_transform_partial_failure(op, request):
ser = Series(3 * [object])

expected = ser.transform(["shift"])
result = ser.transform([op, "shift"])
match = rf"\['{op}'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = ser.transform([op, "shift"])
tm.assert_equal(result, expected)

expected = ser.transform({"B": "shift"})
result = ser.transform({"A": op, "B": "shift"})
match = r"\['A'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = ser.transform({"A": op, "B": "shift"})
tm.assert_equal(result, expected)

expected = ser.transform({"B": ["shift"]})
result = ser.transform({"A": [op], "B": ["shift"]})
match = r"\['A'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = ser.transform({"A": [op], "B": ["shift"]})
tm.assert_equal(result, expected)

expected = ser.transform({"A": ["shift"], "B": [op]})
result = ser.transform({"A": [op, "shift"], "B": [op]})
match = r"\['B'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
expected = ser.transform({"A": ["shift"], "B": [op]})
match = rf"\['{op}'\] did not transform successfully"
with tm.assert_produces_warning(FutureWarning, match=match):
result = ser.transform({"A": [op, "shift"], "B": [op]})
tm.assert_equal(result, expected)


def test_transform_partial_failure_valueerror():
# GH 40211
match = ".*did not transform successfully and did not raise a TypeError"
match = ".*did not transform successfully"

def noop(x):
return x
Expand All @@ -335,7 +345,7 @@ def raising_op(_):
tm.assert_equal(result, expected)

expected = ser.transform({"A": [noop], "B": [noop]})
with tm.assert_produces_warning(FutureWarning, match=match, check_stacklevel=False):
with tm.assert_produces_warning(FutureWarning, match=match):
result = ser.transform({"A": [noop, raising_op], "B": [noop]})
tm.assert_equal(result, expected)

Expand Down

0 comments on commit 8276a56

Please sign in to comment.