Skip to content

Bug gb cummax #46382

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 3 commits into from
Mar 16, 2022
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/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ Groupby/resample/rolling
- Bug in :meth:`DataFrameGroupby.cumsum` with ``skipna=False`` giving incorrect results (:issue:`46216`)
- Bug in :meth:`.GroupBy.cumsum` with ``timedelta64[ns]`` dtype failing to recognize ``NaT`` as a null value (:issue:`46216`)
- Bug in :meth:`GroupBy.cummin` and :meth:`GroupBy.cummax` with nullable dtypes incorrectly altering the original data in place (:issue:`46220`)
- Bug in :meth:`GroupBy.cummax` with ``int64`` dtype with leading value being the smallest possible int64 (:issue:`46382`)
-

Reshaping
Expand Down
13 changes: 9 additions & 4 deletions pandas/_libs/groupby.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -989,13 +989,18 @@ cdef inline bint _treat_as_na(numeric_object_t val, bint is_datetimelike) nogil:
return False


cdef numeric_t _get_min_or_max(numeric_t val, bint compute_max):
cdef numeric_t _get_min_or_max(numeric_t val, bint compute_max, bint is_datetimelike):
"""
Find either the min or the max supported by numeric_t; 'val' is a placeholder
to effectively make numeric_t an argument.
"""
if numeric_t is int64_t:
return -_int64_max if compute_max else util.INT64_MAX
if compute_max and is_datetimelike:
return -_int64_max
# Note(jbrockmendel) 2022-03-15 for reasons unknown, using util.INT64_MIN
# instead of NPY_NAT here causes build warnings and failure in
# test_cummax_i8_at_implementation_bound
return NPY_NAT if compute_max else util.INT64_MAX
elif numeric_t is int32_t:
return util.INT32_MIN if compute_max else util.INT32_MAX
elif numeric_t is int16_t:
Expand Down Expand Up @@ -1395,7 +1400,7 @@ cdef group_min_max(
nobs = np.zeros((<object>out).shape, dtype=np.int64)

group_min_or_max = np.empty_like(out)
group_min_or_max[:] = _get_min_or_max(<iu_64_floating_t>0, compute_max)
group_min_or_max[:] = _get_min_or_max(<iu_64_floating_t>0, compute_max, is_datetimelike)

if iu_64_floating_t is int64_t:
# TODO: only if is_datetimelike?
Expand Down Expand Up @@ -1564,7 +1569,7 @@ cdef group_cummin_max(
bint isna_entry

accum = np.empty((ngroups, (<object>values).shape[1]), dtype=values.dtype)
accum[:] = _get_min_or_max(<iu_64_floating_t>0, compute_max)
accum[:] = _get_min_or_max(<iu_64_floating_t>0, compute_max, is_datetimelike)

na_val = _get_na_val(<iu_64_floating_t>0, is_datetimelike)

Expand Down
12 changes: 12 additions & 0 deletions pandas/tests/groupby/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,18 @@ def test_cummax(dtypes_for_minmax):
tm.assert_series_equal(result, expected)


def test_cummax_i8_at_implementation_bound():
# the minimum value used to be treated as NPY_NAT+1 instead of NPY_NAT
# for int64 dtype GH#46382
ser = Series([pd.NaT.value + n for n in range(5)])
df = DataFrame({"A": 1, "B": ser, "C": ser.view("M8[ns]")})
gb = df.groupby("A")

res = gb.cummax()
exp = df[["B", "C"]]
tm.assert_frame_equal(res, exp)


@pytest.mark.parametrize("method", ["cummin", "cummax"])
@pytest.mark.parametrize("dtype", ["float", "Int64", "Float64"])
@pytest.mark.parametrize(
Expand Down