diff --git a/doc/source/whatsnew/v1.1.4.rst b/doc/source/whatsnew/v1.1.4.rst index 6cb728800dc68..7d35e8b12b9b8 100644 --- a/doc/source/whatsnew/v1.1.4.rst +++ b/doc/source/whatsnew/v1.1.4.rst @@ -28,6 +28,7 @@ Fixed regressions - Fixed regression in certain offsets (:meth:`pd.offsets.Day() ` and below) no longer being hashable (:issue:`37267`) - Fixed regression in :class:`StataReader` which required ``chunksize`` to be manually set when using an iterator to read a dataset (:issue:`37280`) - Fixed regression in setitem with :meth:`DataFrame.iloc` which raised error when trying to set a value while filtering with a boolean list (:issue:`36741`) +- Fixed regression in setitem with a Series getting aligned before setting the values (:issue:`37427`) - Fixed regression in :attr:`MultiIndex.is_monotonic_increasing` returning wrong results with ``NaN`` in at least one of the levels (:issue:`37220`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/series.py b/pandas/core/series.py index 379c4ac1c9526..2cd861cc11b28 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1048,10 +1048,8 @@ def _set_with_engine(self, key, value): def _set_with(self, key, value): # other: fancy integer or otherwise if isinstance(key, slice): - # extract_array so that if we set e.g. ser[-5:] = ser[:5] - # we get the first five values, and not 5 NaNs indexer = self.index._convert_slice_indexer(key, kind="getitem") - self.iloc[indexer] = extract_array(value, extract_numpy=True) + return self._set_values(indexer, value) else: assert not isinstance(key, tuple) @@ -1069,12 +1067,28 @@ def _set_with(self, key, value): # should be caught by the is_bool_indexer check in __setitem__ if key_type == "integer": if not self.index._should_fallback_to_positional(): - self.loc[key] = value + self._set_labels(key, value) else: - self.iloc[key] = value + self._set_values(key, value) else: self.loc[key] = value + def _set_labels(self, key, value): + key = com.asarray_tuplesafe(key) + indexer: np.ndarray = self.index.get_indexer(key) + mask = indexer == -1 + if mask.any(): + raise KeyError(f"{key[mask]} not in index") + self._set_values(indexer, value) + + def _set_values(self, key, value): + if isinstance(key, Series): + key = key._values + self._mgr = self._mgr.setitem( # type: ignore[assignment] + indexer=key, value=value + ) + self._maybe_update_cacher() + def _set_value(self, label, value, takeable: bool = False): """ Quickly set single value at passed label. diff --git a/pandas/tests/series/indexing/test_getitem.py b/pandas/tests/series/indexing/test_getitem.py index 9f6aab823c3ad..cc448279bfce0 100644 --- a/pandas/tests/series/indexing/test_getitem.py +++ b/pandas/tests/series/indexing/test_getitem.py @@ -290,3 +290,13 @@ def test_getitem_multilevel_scalar_slice_not_implemented( msg = r"\(2000, slice\(3, 4, None\)\)" with pytest.raises(TypeError, match=msg): ser[2000, 3:4] + + +def test_getitem_assignment_series_aligment(): + # https://github.com/pandas-dev/pandas/issues/37427 + # with getitem, when assigning with a Series, it is not first aligned + s = Series(range(10)) + idx = np.array([2, 4, 9]) + s[idx] = Series([10, 11, 12]) + expected = Series([0, 1, 10, 3, 11, 5, 6, 7, 8, 12]) + tm.assert_series_equal(s, expected)