Skip to content

Commit bf05f35

Browse files
authored
BUG: arithmetic ops not propagating mask when combining mask arrays and numpy (#50322)
* BUG: arithmetic ops not propagating mask when combining mask arrays and numpy * Fix mypy
1 parent 07b363e commit bf05f35

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ Timezones
810810
Numeric
811811
^^^^^^^
812812
- Bug in :meth:`DataFrame.add` cannot apply ufunc when inputs contain mixed DataFrame type and Series type (:issue:`39853`)
813+
- Bug in arithmetic operations on :class:`Series` not propagating mask when combining masked dtypes and numpy dtypes (:issue:`45810`, :issue:`42630`)
813814
- Bug in DataFrame reduction methods (e.g. :meth:`DataFrame.sum`) with object dtype, ``axis=1`` and ``numeric_only=False`` would not be coerced to float (:issue:`49551`)
814815
- Bug in :meth:`DataFrame.sem` and :meth:`Series.sem` where an erroneous ``TypeError`` would always raise when using data backed by an :class:`ArrowDtype` (:issue:`49759`)
815816

pandas/core/arrays/masked.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,13 @@ def _propagate_mask(
609609
if other is libmissing.NA:
610610
# GH#45421 don't alter inplace
611611
mask = mask | True
612+
elif is_list_like(other) and len(other) == len(mask):
613+
mask = mask | isna(other)
612614
else:
613615
mask = self._mask | mask
614-
return mask
616+
# Incompatible return value type (got "Optional[ndarray[Any, dtype[bool_]]]",
617+
# expected "ndarray[Any, dtype[bool_]]")
618+
return mask # type: ignore[return-value]
615619

616620
def _arith_method(self, other, op):
617621
op_name = op.__name__

pandas/tests/series/test_arithmetic.py

+19
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,25 @@ def test_arithmetic_with_duplicate_index(self):
307307
expected = Series(Timedelta("9 hours"), index=[2, 2, 3, 3, 4])
308308
tm.assert_series_equal(result, expected)
309309

310+
def test_masked_and_non_masked_propagate_na(self):
311+
# GH#45810
312+
ser1 = Series([0, np.nan], dtype="float")
313+
ser2 = Series([0, 1], dtype="Int64")
314+
result = ser1 * ser2
315+
expected = Series([0, pd.NA], dtype="Float64")
316+
tm.assert_series_equal(result, expected)
317+
318+
def test_mask_div_propagate_na_for_non_na_dtype(self):
319+
# GH#42630
320+
ser1 = Series([15, pd.NA, 5, 4], dtype="Int64")
321+
ser2 = Series([15, 5, np.nan, 4])
322+
result = ser1 / ser2
323+
expected = Series([1.0, pd.NA, pd.NA, 1.0], dtype="Float64")
324+
tm.assert_series_equal(result, expected)
325+
326+
result = ser2 / ser1
327+
tm.assert_series_equal(result, expected)
328+
310329

311330
# ------------------------------------------------------------------
312331
# Comparisons

0 commit comments

Comments
 (0)