Skip to content

Commit 014ea2e

Browse files
authored
BUG: Series.mode with dt64tz or PeriodDtype (#44582)
1 parent 9d55b50 commit 014ea2e

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ Datetimelike
553553
- Bug in addition with a :class:`Tick` object and a ``np.timedelta64`` object incorrectly raising instead of returning :class:`Timedelta` (:issue:`44474`)
554554
- Bug in adding a ``np.timedelta64`` object to a :class:`BusinessDay` or :class:`CustomBusinessDay` object incorrectly raising (:issue:`44532`)
555555
- Bug in :meth:`Index.insert` for inserting ``np.datetime64``, ``np.timedelta64`` or ``tuple`` into :class:`Index` with ``dtype='object'`` with negative loc adding ``None`` and replacing existing value (:issue:`44509`)
556+
- Bug in :meth:`Series.mode` with ``DatetimeTZDtype`` incorrectly returning timezone-naive and ``PeriodDtype`` incorrectly raising (:issue:`41927`)
556557
-
557558

558559
Timedelta

pandas/core/algorithms.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def _reconstruct_data(
215215
if isinstance(values, cls) and values.dtype == dtype:
216216
return values
217217

218-
values = cls._from_sequence(values)
218+
values = cls._from_sequence(values, dtype=dtype)
219219
elif is_bool_dtype(dtype):
220220
values = values.astype(dtype, copy=False)
221221

@@ -960,15 +960,18 @@ def mode(values, dropna: bool = True) -> Series:
960960
original = values
961961

962962
# categorical is a fast-path
963-
if is_categorical_dtype(values):
963+
if is_categorical_dtype(values.dtype):
964964
if isinstance(values, Series):
965965
# TODO: should we be passing `name` below?
966966
return Series(values._values.mode(dropna=dropna), name=values.name)
967967
return values.mode(dropna=dropna)
968968

969-
if dropna and needs_i8_conversion(values.dtype):
970-
mask = values.isnull()
971-
values = values[~mask]
969+
if needs_i8_conversion(values.dtype):
970+
if dropna:
971+
mask = values.isna()
972+
values = values[~mask]
973+
modes = mode(values.view("i8"))
974+
return modes.view(original.dtype)
972975

973976
values = _ensure_data(values)
974977

pandas/core/series.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1972,7 +1972,7 @@ def count(self, level=None):
19721972
self, method="count"
19731973
)
19741974

1975-
def mode(self, dropna=True) -> Series:
1975+
def mode(self, dropna: bool = True) -> Series:
19761976
"""
19771977
Return the mode(s) of the Series.
19781978

pandas/tests/series/test_reductions.py

+22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@
77
Series,
88
)
99
import pandas._testing as tm
10+
from pandas.core.algorithms import mode
11+
12+
13+
@pytest.mark.parametrize("as_period", [True, False])
14+
def test_mode_extension_dtype(as_period):
15+
# GH#41927 preserve dt64tz dtype
16+
ser = Series([pd.Timestamp(1979, 4, n) for n in range(1, 5)])
17+
18+
if as_period:
19+
ser = ser.dt.to_period("D")
20+
else:
21+
ser = ser.dt.tz_localize("US/Central")
22+
23+
res = ser.mode()
24+
assert res.dtype == ser.dtype
25+
tm.assert_series_equal(res, ser)
26+
27+
res = mode(ser._values)
28+
tm.assert_series_equal(res, ser)
29+
30+
res = mode(pd.Index(ser))
31+
tm.assert_series_equal(res, ser)
1032

1133

1234
def test_reductions_td64_with_nat():

0 commit comments

Comments
 (0)