diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index eb938a7140e29..016e553cf2092 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -1056,6 +1056,7 @@ MultiIndex - :func:`MultiIndex.get_level_values` accessing a :class:`DatetimeIndex` does not carry the frequency attribute along (:issue:`58327`, :issue:`57949`) - Bug in :class:`DataFrame` arithmetic operations in case of unaligned MultiIndex columns (:issue:`60498`) - Bug in :class:`DataFrame` arithmetic operations with :class:`Series` in case of unaligned MultiIndex (:issue:`61009`) +- Bug in :meth:`MultiIndex.union` raising when indexes have duplicates with differing names (:issue:`62059`) - Bug in :meth:`MultiIndex.from_tuples` causing wrong output with input of type tuples having NaN values (:issue:`60695`, :issue:`60988`) - Bug in :meth:`DataFrame.__setitem__` where column alignment logic would reindex the assigned value with an empty index, incorrectly setting all values to ``NaN``.(:issue:`61841`) - Bug in :meth:`DataFrame.reindex` and :meth:`Series.reindex` where reindexing :class:`Index` to a :class:`MultiIndex` would incorrectly set all values to ``NaN``.(:issue:`60923`) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 0cd33491d68bb..0a4e1f011f06a 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -3946,7 +3946,9 @@ def _union(self, other, sort) -> MultiIndex: if other.has_duplicates: # This is only necessary if other has dupes, # otherwise difference is faster - result = super()._union(other, sort) + result = super(MultiIndex, self.rename(result_names))._union( + other.rename(result_names), sort + ) if isinstance(result, MultiIndex): return result diff --git a/pandas/tests/indexes/multi/test_setops.py b/pandas/tests/indexes/multi/test_setops.py index f7544cf62e5fa..cd8c714f9a146 100644 --- a/pandas/tests/indexes/multi/test_setops.py +++ b/pandas/tests/indexes/multi/test_setops.py @@ -687,6 +687,18 @@ def test_union_keep_ea_dtype_with_na(any_numeric_ea_dtype): tm.assert_index_equal(result, expected) +def test_union_duplicates_different_names(): + # GH#62059 + mi1 = MultiIndex.from_tuples([(1, "a"), (2, "b")], names=["x", "y"]) + mi2 = MultiIndex.from_tuples([(2, "b"), (3, "c"), (2, "b")]) + + result = mi1.union(mi2) + expected = MultiIndex.from_tuples( + [(1, "a"), (2, "b"), (2, "b"), (3, "c")], names=[None, None] + ) + tm.assert_index_equal(result, expected) + + @pytest.mark.parametrize( "levels1, levels2, codes1, codes2, names", [