Skip to content

Commit 1aa7c2c

Browse files
behzadnourijreback
authored andcommitted
BUG: apply Series mask to aligned new values (GH8387)
1 parent 9b46a69 commit 1aa7c2c

File tree

3 files changed

+29
-6
lines changed

3 files changed

+29
-6
lines changed

doc/source/v0.15.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -986,3 +986,4 @@ Bug Fixes
986986
(:issue:`5884').
987987
- Bug in ``DataFrame.dropna`` that interpreted non-existent columns in the subset argument as the 'last column' (:issue:`8303`)
988988
- Bug in Index.intersection on non-monotonic non-unique indexes (:issue:`8362`).
989+
- Bug in masked series assignment where mismatching types would break alignment (:issue:`8387`)

pandas/core/internals.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -3924,14 +3924,16 @@ def _putmask_smart(v, m, n):
39243924
39253925
Parameters
39263926
----------
3927-
v : array_like
3928-
m : array_like
3929-
n : array_like
3927+
v : `values`, updated in-place (array like)
3928+
m : `mask`, applies to both sides (array like)
3929+
n : `new values` either scalar or an array like aligned with `values`
39303930
"""
39313931

39323932
# n should be the length of the mask or a scalar here
39333933
if not is_list_like(n):
39343934
n = np.array([n] * len(m))
3935+
elif isinstance(n, np.ndarray) and n.ndim == 0: # numpy scalar
3936+
n = np.repeat(np.array(n, ndmin=1), len(m))
39353937

39363938
# see if we are only masking values that if putted
39373939
# will work in the current dtype
@@ -3949,10 +3951,10 @@ def _putmask_smart(v, m, n):
39493951
dtype, _ = com._maybe_promote(n.dtype)
39503952
nv = v.astype(dtype)
39513953
try:
3952-
nv[m] = n
3954+
nv[m] = n[m]
39533955
except ValueError:
39543956
idx, = np.where(np.squeeze(m))
3955-
for mask_index, new_val in zip(idx, n):
3957+
for mask_index, new_val in zip(idx, n[m]):
39563958
nv[mask_index] = new_val
39573959
return nv
39583960

pandas/tests/test_series.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -5014,6 +5014,27 @@ def test_cast_on_putmask(self):
50145014

50155015
assert_series_equal(s, expected)
50165016

5017+
def test_type_promote_putmask(self):
5018+
5019+
# GH8387: test that changing types does not break alignment
5020+
ts = Series(np.random.randn(100), index=np.arange(100,0,-1)).round(5)
5021+
left, mask = ts.copy(), ts > 0
5022+
right = ts[mask].copy().map(str)
5023+
left[mask] = right
5024+
assert_series_equal(left, ts.map(lambda t: str(t) if t > 0 else t))
5025+
5026+
s = Series([0, 1, 2, 0 ])
5027+
mask = s > 0
5028+
s2 = s[ mask ].map( str )
5029+
s[mask] = s2
5030+
assert_series_equal(s, Series([0, '1', '2', 0]))
5031+
5032+
s = Series([0, 'foo', 'bar', 0 ])
5033+
mask = Series([False, True, True, False])
5034+
s2 = s[ mask ]
5035+
s[mask] = s2
5036+
assert_series_equal(s, Series([0, 'foo','bar', 0]))
5037+
50175038
def test_astype_cast_nan_int(self):
50185039
df = Series([1.0, 2.0, 3.0, np.nan])
50195040
self.assertRaises(ValueError, df.astype, np.int64)
@@ -6286,4 +6307,3 @@ def test_unique_data_ownership(self):
62866307
if __name__ == '__main__':
62876308
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
62886309
exit=False)
6289-

0 commit comments

Comments
 (0)