diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index ea5258cf1537d..1084bcc1eeeb5 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -316,6 +316,7 @@ Indexing ^^^^^^^^ - Bug in :meth:`loc.__getitem__` with a list of keys causing an internal inconsistency that could lead to a disconnect between ``frame.at[x, y]`` vs ``frame[y].loc[x]`` (:issue:`22372`) - Bug in :meth:`DataFrame.iloc` where indexing a single row on a :class:`DataFrame` with a single ExtensionDtype column gave a copy instead of a view on the underlying data (:issue:`45241`) +- Bug in :meth:`Series.align` does not create :class:`MultiIndex` with union of levels when both MultiIndexes intersections are identical (:issue:`45224`) - Bug in setting a NA value (``None`` or ``np.nan``) into a :class:`Series` with int-based :class:`IntervalDtype` incorrectly casting to object dtype instead of a float-based :class:`IntervalDtype` (:issue:`45568`) - Bug in :meth:`Series.__setitem__` with a non-integer :class:`Index` when using an integer key to set a value that cannot be set inplace where a ``ValueError`` was raised instead of casting to a common dtype (:issue:`45070`) - Bug in :meth:`Series.__setitem__` when setting incompatible values into a ``PeriodDtype`` or ``IntervalDtype`` :class:`Series` raising when indexing with a boolean mask but coercing when indexing with otherwise-equivalent indexers; these now consistently coerce, along with :meth:`Series.mask` and :meth:`Series.where` (:issue:`45768`) diff --git a/pandas/core/series.py b/pandas/core/series.py index ea80f9d1ea04e..efbf8ecf74f1f 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4502,7 +4502,9 @@ def _reindex_indexer( ) -> Series: # Note: new_index is None iff indexer is None # if not None, indexer is np.intp - if indexer is None: + if indexer is None and ( + new_index is None or new_index.names == self.index.names + ): if copy: return self.copy() return self diff --git a/pandas/tests/series/methods/test_align.py b/pandas/tests/series/methods/test_align.py index 8769ab048a136..33e2b1ccecf2d 100644 --- a/pandas/tests/series/methods/test_align.py +++ b/pandas/tests/series/methods/test_align.py @@ -184,3 +184,41 @@ def test_align_periodindex(join_type): # TODO: assert something? ts.align(ts[::2], join=join_type) + + +def test_align_left_fewer_levels(): + # GH#45224 + left = Series([2], index=pd.MultiIndex.from_tuples([(1, 3)], names=["a", "c"])) + right = Series( + [1], index=pd.MultiIndex.from_tuples([(1, 2, 3)], names=["a", "b", "c"]) + ) + result_left, result_right = left.align(right) + + expected_right = Series( + [1], index=pd.MultiIndex.from_tuples([(1, 3, 2)], names=["a", "c", "b"]) + ) + expected_left = Series( + [2], index=pd.MultiIndex.from_tuples([(1, 3, 2)], names=["a", "c", "b"]) + ) + tm.assert_series_equal(result_left, expected_left) + tm.assert_series_equal(result_right, expected_right) + + +def test_align_left_different_named_levels(): + # GH#45224 + left = Series( + [2], index=pd.MultiIndex.from_tuples([(1, 4, 3)], names=["a", "d", "c"]) + ) + right = Series( + [1], index=pd.MultiIndex.from_tuples([(1, 2, 3)], names=["a", "b", "c"]) + ) + result_left, result_right = left.align(right) + + expected_left = Series( + [2], index=pd.MultiIndex.from_tuples([(1, 3, 4, 2)], names=["a", "c", "d", "b"]) + ) + expected_right = Series( + [1], index=pd.MultiIndex.from_tuples([(1, 3, 4, 2)], names=["a", "c", "d", "b"]) + ) + tm.assert_series_equal(result_left, expected_left) + tm.assert_series_equal(result_right, expected_right) diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index f2b561c77d246..1ffdb10369134 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -885,8 +885,8 @@ def test_series_varied_multiindex_alignment(): expected = Series( [1000, 2001, 3002, 4003], index=pd.MultiIndex.from_tuples( - [("a", "x", 1), ("a", "x", 2), ("a", "y", 1), ("a", "y", 2)], - names=["ab", "xy", "num"], + [("x", 1, "a"), ("x", 2, "a"), ("y", 1, "a"), ("y", 2, "a")], + names=["xy", "num", "ab"], ), ) tm.assert_series_equal(result, expected)