diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f91d40c4d9ea9..16563ace81b47 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -994,6 +994,7 @@ MultiIndex - 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.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`) I/O diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 473f69591aa70..a74c947504833 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -4450,6 +4450,11 @@ def _set_item_frame_value(self, key, value: DataFrame) -> None: loc, (slice, Series, np.ndarray, Index) ): cols_droplevel = maybe_droplevels(cols, key) + if ( + not isinstance(cols_droplevel, MultiIndex) + and not cols_droplevel.any() + ): + return if len(cols_droplevel) and not cols_droplevel.equals(value.columns): value = value.reindex(cols_droplevel, axis=1) diff --git a/pandas/tests/indexing/multiindex/test_multiindex.py b/pandas/tests/indexing/multiindex/test_multiindex.py index 7140ad7d1e9f5..2fe8f9affba2d 100644 --- a/pandas/tests/indexing/multiindex/test_multiindex.py +++ b/pandas/tests/indexing/multiindex/test_multiindex.py @@ -249,3 +249,25 @@ def test_groupyby_rename_categories_operation_with_multiindex(self, operation): expected = getattr(a, operation)(b.sort_index(ascending=False)) tm.assert_series_equal(result, expected) + + def test_multiindex_assign_aligns_as_implicit_tuple(self): + # GH 61841 + cols = MultiIndex.from_tuples([("A", "B")]) + df1 = DataFrame([[i] for i in range(3)], columns=cols) + df2 = df1.copy() + df3 = df1.copy() + s1 = df1["A"].rolling(2).mean() + s2 = s1.copy() + s3 = s1.copy() + + df2["C"] = s2 + df3[("C", "")] = s3 + tm.assert_frame_equal(df2, df3) + + df1["C"] = s1 + tm.assert_frame_equal(df1, df2) + tm.assert_frame_equal(df1, df3) + + df1["C"] = s1 + tm.assert_frame_equal(df1, df2) + tm.assert_frame_equal(df1, df3)