From f6f1b978d81bd2a63bf08e33f5ccd5aa7b6e60b0 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Fri, 14 Oct 2022 10:53:03 +0200 Subject: [PATCH] REGR: midx.values resetting freq of underyling index --- doc/source/whatsnew/v1.5.1.rst | 1 + pandas/core/indexes/multi.py | 10 ++++++---- pandas/tests/indexes/multi/test_get_level_values.py | 11 +++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v1.5.1.rst b/doc/source/whatsnew/v1.5.1.rst index 2fca23024cba7..4518c6f544e48 100644 --- a/doc/source/whatsnew/v1.5.1.rst +++ b/doc/source/whatsnew/v1.5.1.rst @@ -76,6 +76,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.loc` raising ``FutureWarning`` when setting an empty :class:`DataFrame` (:issue:`48480`) - Fixed regression in :meth:`DataFrame.describe` raising ``TypeError`` when result contains ``NA`` (:issue:`48778`) - Fixed regression in :meth:`DataFrame.plot` ignoring invalid ``colormap`` for ``kind="scatter"`` (:issue:`48726`) +- Fixed regression in :meth:`MultiIndex.values`` resetting ``freq`` attribute of underlying :class:`Index` object (:issue:`49054`) - Fixed performance regression in :func:`factorize` when ``na_sentinel`` is not ``None`` and ``sort=False`` (:issue:`48620`) - Fixed regression causing an ``AttributeError`` during warning emitted if the provided table name in :meth:`DataFrame.to_sql` and the table name actually used in the database do not match (:issue:`48733`) - Fixed regression in :func:`to_datetime` when ``arg`` was a date string with nanosecond and ``format`` contained ``%f`` would raise a ``ValueError`` (:issue:`48767`) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 646020d5af9bf..a02e30bc89939 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -734,13 +734,14 @@ def _values(self) -> np.ndarray: vals = cast("CategoricalIndex", vals) vals = vals._data._internal_get_values() - if isinstance(vals, ABCDatetimeIndex): + is_dti = isinstance(vals, ABCDatetimeIndex) + + if is_dti: # TODO: this can be removed after Timestamp.freq is removed # The astype(object) below does not remove the freq from # the underlying Timestamps so we remove it here to match # the behavior of self._get_level_values - vals = vals.copy() - vals.freq = None + vals = algos.take_nd(vals, codes, fill_value=index._na_value) if isinstance(vals.dtype, ExtensionDtype) or isinstance( vals, (ABCDatetimeIndex, ABCTimedeltaIndex) @@ -748,7 +749,8 @@ def _values(self) -> np.ndarray: vals = vals.astype(object) vals = np.array(vals, copy=False) - vals = algos.take_nd(vals, codes, fill_value=index._na_value) + if not is_dti: + vals = algos.take_nd(vals, codes, fill_value=index._na_value) values.append(vals) arr = lib.fast_zip(values) diff --git a/pandas/tests/indexes/multi/test_get_level_values.py b/pandas/tests/indexes/multi/test_get_level_values.py index 300df00d6151c..bab6481fe107f 100644 --- a/pandas/tests/indexes/multi/test_get_level_values.py +++ b/pandas/tests/indexes/multi/test_get_level_values.py @@ -112,3 +112,14 @@ def test_get_level_values_when_periods(): [idx._get_level_values(level) for level in range(idx.nlevels)] ) assert all(x.is_monotonic_increasing for x in idx2.levels) + + +def test_values_loses_freq_of_underlying_index(): + # GH#49054 + idx = pd.DatetimeIndex(date_range("20200101", periods=3, freq="BM")) + expected = idx.copy(deep=True) + idx2 = Index([1, 2, 3]) + midx = MultiIndex(levels=[idx, idx2], codes=[[0, 1, 2], [0, 1, 2]]) + midx.values + assert idx.freq is not None + tm.assert_index_equal(idx, expected)