Skip to content

Commit 9aa01e8

Browse files
Merge branch 'master' into fix-crosstab-cats
2 parents ea22f10 + d8c8cbb commit 9aa01e8

File tree

6 files changed

+50
-5
lines changed

6 files changed

+50
-5
lines changed

doc/source/whatsnew/v1.1.4.rst

+2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ Fixed regressions
2828
- Fixed regression in certain offsets (:meth:`pd.offsets.Day() <pandas.tseries.offsets.Day>` and below) no longer being hashable (:issue:`37267`)
2929
- Fixed regression in :class:`StataReader` which required ``chunksize`` to be manually set when using an iterator to read a dataset (:issue:`37280`)
3030
- 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`)
31+
- Fixed regression in setitem with a Series getting aligned before setting the values (:issue:`37427`)
3132
- Fixed regression in :attr:`MultiIndex.is_monotonic_increasing` returning wrong results with ``NaN`` in at least one of the levels (:issue:`37220`)
3233
- Fixed regression in :meth:`crosstab` that failed when the input series are categorical. (:issue:`37465`)
34+
- Fixed regression in inplace arithmetic operation on a Series not updating the parent DataFrame (:issue:`36373`)
3335

3436
.. ---------------------------------------------------------------------------
3537

pandas/core/generic.py

+5
Original file line numberDiff line numberDiff line change
@@ -11115,6 +11115,11 @@ def _inplace_method(self, other, op):
1111511115
"""
1111611116
result = op(self, other)
1111711117

11118+
if self.ndim == 1 and result._indexed_same(self) and result.dtype == self.dtype:
11119+
# GH#36498 this inplace op can _actually_ be inplace.
11120+
self._values[:] = result._values
11121+
return self
11122+
1111811123
# Delete cacher
1111911124
self._reset_cacher()
1112011125

pandas/core/series.py

+19-5
Original file line numberDiff line numberDiff line change
@@ -1048,10 +1048,8 @@ def _set_with_engine(self, key, value):
10481048
def _set_with(self, key, value):
10491049
# other: fancy integer or otherwise
10501050
if isinstance(key, slice):
1051-
# extract_array so that if we set e.g. ser[-5:] = ser[:5]
1052-
# we get the first five values, and not 5 NaNs
10531051
indexer = self.index._convert_slice_indexer(key, kind="getitem")
1054-
self.iloc[indexer] = extract_array(value, extract_numpy=True)
1052+
return self._set_values(indexer, value)
10551053

10561054
else:
10571055
assert not isinstance(key, tuple)
@@ -1069,12 +1067,28 @@ def _set_with(self, key, value):
10691067
# should be caught by the is_bool_indexer check in __setitem__
10701068
if key_type == "integer":
10711069
if not self.index._should_fallback_to_positional():
1072-
self.loc[key] = value
1070+
self._set_labels(key, value)
10731071
else:
1074-
self.iloc[key] = value
1072+
self._set_values(key, value)
10751073
else:
10761074
self.loc[key] = value
10771075

1076+
def _set_labels(self, key, value):
1077+
key = com.asarray_tuplesafe(key)
1078+
indexer: np.ndarray = self.index.get_indexer(key)
1079+
mask = indexer == -1
1080+
if mask.any():
1081+
raise KeyError(f"{key[mask]} not in index")
1082+
self._set_values(indexer, value)
1083+
1084+
def _set_values(self, key, value):
1085+
if isinstance(key, Series):
1086+
key = key._values
1087+
self._mgr = self._mgr.setitem( # type: ignore[assignment]
1088+
indexer=key, value=value
1089+
)
1090+
self._maybe_update_cacher()
1091+
10781092
def _set_value(self, label, value, takeable: bool = False):
10791093
"""
10801094
Quickly set single value at passed label.

pandas/tests/frame/test_arithmetic.py

+13
Original file line numberDiff line numberDiff line change
@@ -1698,3 +1698,16 @@ def test_arith_list_of_arraylike_raise(to_add):
16981698
df + to_add
16991699
with pytest.raises(ValueError, match=msg):
17001700
to_add + df
1701+
1702+
1703+
def test_inplace_arithmetic_series_update():
1704+
# https://github.com/pandas-dev/pandas/issues/36373
1705+
df = DataFrame({"A": [1, 2, 3]})
1706+
series = df["A"]
1707+
vals = series._values
1708+
1709+
series += 1
1710+
assert series._values is vals
1711+
1712+
expected = DataFrame({"A": [2, 3, 4]})
1713+
tm.assert_frame_equal(df, expected)

pandas/tests/indexing/test_loc.py

+1
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,7 @@ def test_identity_slice_returns_new_object(self):
888888
original_series[:3] = [7, 8, 9]
889889
assert all(sliced_series[:3] == [7, 8, 9])
890890

891+
@pytest.mark.xfail(reason="accidental fix reverted - GH37497")
891892
def test_loc_copy_vs_view(self):
892893
# GH 15631
893894
x = DataFrame(zip(range(3), range(3)), columns=["a", "b"])

pandas/tests/series/indexing/test_getitem.py

+10
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,13 @@ def test_getitem_multilevel_scalar_slice_not_implemented(
290290
msg = r"\(2000, slice\(3, 4, None\)\)"
291291
with pytest.raises(TypeError, match=msg):
292292
ser[2000, 3:4]
293+
294+
295+
def test_getitem_assignment_series_aligment():
296+
# https://github.com/pandas-dev/pandas/issues/37427
297+
# with getitem, when assigning with a Series, it is not first aligned
298+
s = Series(range(10))
299+
idx = np.array([2, 4, 9])
300+
s[idx] = Series([10, 11, 12])
301+
expected = Series([0, 1, 10, 3, 11, 5, 6, 7, 8, 12])
302+
tm.assert_series_equal(s, expected)

0 commit comments

Comments
 (0)