From d285e5ad46db2e10009e81df1b5d4bdd2ecdf80b Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 18 Jan 2021 22:31:58 +0100 Subject: [PATCH 1/3] REGR: fix numpy accumulate ufuncs for DataFrame --- doc/source/whatsnew/v1.2.1.rst | 1 + pandas/core/arraylike.py | 9 +++++++-- pandas/tests/frame/test_ufunc.py | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.2.1.rst b/doc/source/whatsnew/v1.2.1.rst index 24ba9be4383eb..77628866b8f18 100644 --- a/doc/source/whatsnew/v1.2.1.rst +++ b/doc/source/whatsnew/v1.2.1.rst @@ -31,6 +31,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.replace` raising ``ValueError`` when :class:`DataFrame` has dtype ``bytes`` (:issue:`38900`) - Fixed regression in :meth:`Series.fillna` that raised ``RecursionError`` with ``datetime64[ns, UTC]`` dtype (:issue:`38851`) - Fixed regression in comparisons between ``NaT`` and ``datetime.date`` objects incorrectly returning ``True`` (:issue:`39151`) +- Fixed regression in calling NumPy ``accumulate`` ufuncs on DataFrames (:issue:`39259`) - Fixed regression in repr of float-like strings of an ``object`` dtype having trailing 0's truncated after the decimal (:issue:`38708`) - Fixed regression that raised ``AttributeError`` with PyArrow versions [0.16.0, 1.0.0) (:issue:`38801`) - Fixed regression in :func:`pandas.testing.assert_frame_equal` raising ``TypeError`` with ``check_like=True`` when :class:`Index` or columns have mixed dtype (:issue:`39168`) diff --git a/pandas/core/arraylike.py b/pandas/core/arraylike.py index 6b28f8f135769..c01a8382b77ef 100644 --- a/pandas/core/arraylike.py +++ b/pandas/core/arraylike.py @@ -274,8 +274,13 @@ def reconstruct(result): result = getattr(ufunc, method)(*inputs, **kwargs) else: # ufunc(dataframe) - mgr = inputs[0]._mgr - result = mgr.apply(getattr(ufunc, method)) + if method == "__call__": + mgr = inputs[0]._mgr + result = mgr.apply(getattr(ufunc, method)) + else: + # specific ufunc methods (eg accumulate) have an axis keyword + # and thus can't be called block-by-block + result = getattr(ufunc, method)(np.asarray(inputs[0]), **kwargs) if ufunc.nout > 1: # type: ignore[attr-defined] result = tuple(reconstruct(x) for x in result) diff --git a/pandas/tests/frame/test_ufunc.py b/pandas/tests/frame/test_ufunc.py index 8a29c2f2f89a1..92e81ec3faaa0 100644 --- a/pandas/tests/frame/test_ufunc.py +++ b/pandas/tests/frame/test_ufunc.py @@ -117,6 +117,27 @@ def test_binary_frame_series_raises(): np.logaddexp(df["A"], df) +def test_unary_accumulate_axis(): + # https://github.com/pandas-dev/pandas/issues/39259 + df = pd.DataFrame({"a": [1, 3, 2, 4]}) + result = np.maximum.accumulate(df) + expected = pd.DataFrame({"a": [1, 3, 3, 4]}) + tm.assert_frame_equal(result, expected) + + df = pd.DataFrame({"a": [1, 3, 2, 4], "b": [0.1, 4.0, 3.0, 2.0]}) + result = np.maximum.accumulate(df) + # in theory could preserve int dtype for default axis=0 + expected = pd.DataFrame({"a": [1.0, 3.0, 3.0, 4.0], "b": [0.1, 4.0, 4.0, 4.0]}) + tm.assert_frame_equal(result, expected) + + result = np.maximum.accumulate(df, axis=0) + tm.assert_frame_equal(result, expected) + + result = np.maximum.accumulate(df, axis=1) + expected = pd.DataFrame({"a": [1.0, 3.0, 2.0, 4.0], "b": [1.0, 4.0, 3.0, 4.0]}) + tm.assert_frame_equal(result, expected) + + def test_frame_outer_deprecated(): df = pd.DataFrame({"A": [1, 2]}) with tm.assert_produces_warning(FutureWarning): From 668a9d2945e04cc442889108e8b2a38764a3dde1 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Tue, 19 Jan 2021 15:52:53 +0100 Subject: [PATCH 2/3] add example + clarifying notes --- doc/source/whatsnew/v1.2.1.rst | 2 +- pandas/core/arraylike.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v1.2.1.rst b/doc/source/whatsnew/v1.2.1.rst index 77628866b8f18..f7816da50beb7 100644 --- a/doc/source/whatsnew/v1.2.1.rst +++ b/doc/source/whatsnew/v1.2.1.rst @@ -31,7 +31,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.replace` raising ``ValueError`` when :class:`DataFrame` has dtype ``bytes`` (:issue:`38900`) - Fixed regression in :meth:`Series.fillna` that raised ``RecursionError`` with ``datetime64[ns, UTC]`` dtype (:issue:`38851`) - Fixed regression in comparisons between ``NaT`` and ``datetime.date`` objects incorrectly returning ``True`` (:issue:`39151`) -- Fixed regression in calling NumPy ``accumulate`` ufuncs on DataFrames (:issue:`39259`) +- Fixed regression in calling NumPy ``accumulate`` ufuncs on DataFrames, e.g. ``np.maximum.accumulate(df)`` (:issue:`39259`) - Fixed regression in repr of float-like strings of an ``object`` dtype having trailing 0's truncated after the decimal (:issue:`38708`) - Fixed regression that raised ``AttributeError`` with PyArrow versions [0.16.0, 1.0.0) (:issue:`38801`) - Fixed regression in :func:`pandas.testing.assert_frame_equal` raising ``TypeError`` with ``check_like=True`` when :class:`Index` or columns have mixed dtype (:issue:`39168`) diff --git a/pandas/core/arraylike.py b/pandas/core/arraylike.py index c01a8382b77ef..c9b9cedb1d9a4 100644 --- a/pandas/core/arraylike.py +++ b/pandas/core/arraylike.py @@ -275,11 +275,12 @@ def reconstruct(result): else: # ufunc(dataframe) if method == "__call__": + # for np.(..) calls mgr = inputs[0]._mgr result = mgr.apply(getattr(ufunc, method)) else: - # specific ufunc methods (eg accumulate) have an axis keyword - # and thus can't be called block-by-block + # otherwise specific ufunc methods (eg np..accumulate(..)) + # Those can have an axis keyword and thus can't be called block-by-block result = getattr(ufunc, method)(np.asarray(inputs[0]), **kwargs) if ufunc.nout > 1: # type: ignore[attr-defined] From 13dcd5c89af0941057aabe00db157b202cc840ad Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Tue, 19 Jan 2021 16:12:14 +0100 Subject: [PATCH 3/3] add reference to numpy docs --- doc/source/whatsnew/v1.2.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.2.1.rst b/doc/source/whatsnew/v1.2.1.rst index 69e3123aa1068..4d41a2998bbb5 100644 --- a/doc/source/whatsnew/v1.2.1.rst +++ b/doc/source/whatsnew/v1.2.1.rst @@ -32,7 +32,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.replace` raising ``ValueError`` when :class:`DataFrame` has dtype ``bytes`` (:issue:`38900`) - Fixed regression in :meth:`Series.fillna` that raised ``RecursionError`` with ``datetime64[ns, UTC]`` dtype (:issue:`38851`) - Fixed regression in comparisons between ``NaT`` and ``datetime.date`` objects incorrectly returning ``True`` (:issue:`39151`) -- Fixed regression in calling NumPy ``accumulate`` ufuncs on DataFrames, e.g. ``np.maximum.accumulate(df)`` (:issue:`39259`) +- Fixed regression in calling NumPy :func:`~numpy.ufunc.accumulate` ufuncs on DataFrames, e.g. ``np.maximum.accumulate(df)`` (:issue:`39259`) - Fixed regression in repr of float-like strings of an ``object`` dtype having trailing 0's truncated after the decimal (:issue:`38708`) - Fixed regression that raised ``AttributeError`` with PyArrow versions [0.16.0, 1.0.0) (:issue:`38801`) - Fixed regression in :func:`pandas.testing.assert_frame_equal` raising ``TypeError`` with ``check_like=True`` when :class:`Index` or columns have mixed dtype (:issue:`39168`)