Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ Indexing
- Bug in :meth:`DataFrame.loc` and :meth:`Series.loc` replacing the index name with the key's name when indexing with an :class:`Index` (:issue:`17110`)
- Bug in :meth:`DataFrame.loc` raising ``ValueError`` when setting a row on a :class:`DataFrame` with no columns and the label is not in the index (:issue:`17895`)
- Bug in :meth:`DataFrame.loc` returning incorrect dtype when the column key is a ``slice`` (:issue:`63071`)
- Bug in :meth:`DataFrame.loc` where setting a scalar column with a :class:`DataFrame` value failed to align indices properly (:issue:`58482`)
- Bug in :meth:`Index.get_indexer` where ``method="pad"``, ``"backfill"``, or ``"nearest"`` returned incorrect results when the target contained ``NaT`` or ``NaN`` instead of ``-1`` (:issue:`32572`)
- Bugs in setitem-with-expansion when adding new rows failing to keep the original dtype in some cases (:issue:`32346`, :issue:`15231`, :issue:`47503`, :issue:`6485`, :issue:`25383`, :issue:`52235`, :issue:`17026`, :issue:`56010`)
- Bug in :meth:`DataFrame.__getitem__` raising ``InvalidIndexError`` when indexing with a tuple containing a ``slice`` on a :class:`DataFrame` with :class:`MultiIndex` columns (e.g., ``df[:, "t1"]``) (:issue:`26511`)
Expand Down
23 changes: 18 additions & 5 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2834,6 +2834,24 @@ def _setitem_single_block(self, indexer, value, name: str) -> None:

info_axis = self.obj._info_axis_number
item_labels = self.obj._get_axis(info_axis)

if isinstance(indexer, tuple):
indexer = maybe_convert_ix(*indexer) # e.g. test_setitem_frame_align

if isinstance(value, ABCDataFrame) and name != "iloc":
if (
isinstance(indexer, tuple)
and self.ndim == len(indexer) == 2
and is_integer(indexer[info_axis])
):
col = item_labels[indexer[info_axis]]
if col in value.columns:
value = self._align_series(indexer, value[col])
else:
value = np.nan
else:
value = self._align_frame(indexer, value)._values

if isinstance(indexer, tuple):
# if we are setting on the info axis ONLY
# set using those methods to avoid block-splitting
Expand All @@ -2850,11 +2868,6 @@ def _setitem_single_block(self, indexer, value, name: str) -> None:
self._setitem_single_column(loc, value, indexer[0])
return

indexer = maybe_convert_ix(*indexer) # e.g. test_setitem_frame_align

if isinstance(value, ABCDataFrame) and name != "iloc":
value = self._align_frame(indexer, value)._values

# actually do the set
self.obj._mgr = self.obj._mgr.setitem(indexer=indexer, value=value)

Expand Down
25 changes: 18 additions & 7 deletions pandas/tests/indexing/test_loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1514,13 +1514,9 @@ def test_loc_setitem_datetimeindex_tz(self, idxer, tz_naive_fixture):
# if result started off with object dtype, then the .loc.__setitem__
# below would retain object dtype
result = DataFrame(index=idx, columns=["var"], dtype=np.float64)
if idxer == "var":
with pytest.raises(TypeError, match="Invalid value"):
result.loc[:, idxer] = expected
else:
# See https://github.com/pandas-dev/pandas/issues/56223
result.loc[:, idxer] = expected
tm.assert_frame_equal(result, expected)
# See https://github.com/pandas-dev/pandas/issues/56223
result.loc[:, idxer] = expected
tm.assert_frame_equal(result, expected)

def test_loc_setitem_time_key(self):
index = date_range("2012-01-01", "2012-01-05", freq="30min")
Expand Down Expand Up @@ -3755,3 +3751,18 @@ def test_loc_setitem_extension_array_into_object_series():
ser.loc[:] = arr
expected = Series(list(arr), dtype=object)
tm.assert_series_equal(ser, expected)


class TestLocSetitemDataFrameAlignment:
def test_loc_setitem_scalar_column_dataframe_alignment(self):
# GH 58482
df = DataFrame([[1.0, 2], [3.0, 4]], index=["x", "y"], columns=["A", "B"])
item = DataFrame([100], columns=["A"], index=["v"])

# Setting a single block dataframe's column with a dataframe should align
df.loc[:, "A"] = item

expected = DataFrame(
[[np.nan, 2], [np.nan, 4]], index=["x", "y"], columns=["A", "B"]
)
tm.assert_frame_equal(df, expected)
Loading