diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index a940a1a1c0a08..a2d05ba11bc79 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -838,6 +838,7 @@ MultiIndex - Bug in :meth:`MultiIndex.get_loc` raising ``TypeError`` instead of ``KeyError`` on nested tuple (:issue:`42440`) - Bug in :meth:`MultiIndex.union` setting wrong ``sortorder`` causing errors in subsequent indexing operations with slices (:issue:`44752`) - Bug in :meth:`MultiIndex.putmask` where the other value was also a :class:`MultiIndex` (:issue:`43212`) +- Bug in :meth:`MultiIndex.dtypes` duplicate level names returned only one dtype per name (:issue:`45174`) - I/O diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 830f3afc8a1e7..816fa3abb618c 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -739,9 +739,7 @@ def dtypes(self) -> Series: from pandas import Series names = com.fill_missing_names([level.name for level in self.levels]) - return Series( - {names[idx]: level.dtype for idx, level in enumerate(self.levels)} - ) + return Series([level.dtype for level in self.levels], index=names) def __len__(self) -> int: return len(self.codes[0]) diff --git a/pandas/tests/indexes/multi/test_get_set.py b/pandas/tests/indexes/multi/test_get_set.py index e806ee1751b00..aa0e91cecd4fc 100644 --- a/pandas/tests/indexes/multi/test_get_set.py +++ b/pandas/tests/indexes/multi/test_get_set.py @@ -67,6 +67,23 @@ def test_get_dtypes_no_level_name(): tm.assert_series_equal(expected, idx_multitype.dtypes) +def test_get_dtypes_duplicate_level_names(): + # Test MultiIndex.dtypes with non-unique level names (# GH45174) + result = MultiIndex.from_product( + [ + [1, 2, 3], + ["a", "b", "c"], + pd.date_range("20200101", periods=2, tz="UTC"), + ], + names=["A", "A", "A"], + ).dtypes + expected = pd.Series( + [np.dtype("int64"), np.dtype("O"), DatetimeTZDtype(tz="utc")], + index=["A", "A", "A"], + ) + tm.assert_series_equal(result, expected) + + def test_get_level_number_out_of_bounds(multiindex_dataframe_random_data): frame = multiindex_dataframe_random_data