Skip to content

Commit f63e7b8

Browse files
authored
BUG: Series add casting to object for list and masked series (#50762)
* BUG: Series add casting to object for list and masked series * Fix boolean * Fix length missmatch
1 parent 8d296f2 commit f63e7b8

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

doc/source/whatsnew/v2.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,7 @@ Numeric
931931
- Bug in arithmetic operations on :class:`Series` not propagating mask when combining masked dtypes and numpy dtypes (:issue:`45810`, :issue:`42630`)
932932
- 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`)
933933
- 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`)
934+
- Bug in :meth:`Series.__add__` casting to object for list and masked :class:`Series` (:issue:`22962`)
934935

935936
Conversion
936937
^^^^^^^^^^

pandas/core/arrays/masked.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,27 @@ def _arith_method(self, other, op):
621621
op_name = op.__name__
622622
omask = None
623623

624+
if (
625+
not hasattr(other, "dtype")
626+
and is_list_like(other)
627+
and len(other) == len(self)
628+
):
629+
# Try inferring masked dtype instead of casting to object
630+
inferred_dtype = lib.infer_dtype(other, skipna=True)
631+
if inferred_dtype == "integer":
632+
from pandas.core.arrays import IntegerArray
633+
634+
other = IntegerArray._from_sequence(other)
635+
elif inferred_dtype in ["floating", "mixed-integer-float"]:
636+
from pandas.core.arrays import FloatingArray
637+
638+
other = FloatingArray._from_sequence(other)
639+
640+
elif inferred_dtype in ["boolean"]:
641+
from pandas.core.arrays import BooleanArray
642+
643+
other = BooleanArray._from_sequence(other)
644+
624645
if isinstance(other, BaseMaskedArray):
625646
other, omask = other._data, other._mask
626647

pandas/tests/series/test_arithmetic.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,27 @@ def test_mask_div_propagate_na_for_non_na_dtype(self):
325325
result = ser2 / ser1
326326
tm.assert_series_equal(result, expected)
327327

328+
@pytest.mark.parametrize("val, dtype", [(3, "Int64"), (3.5, "Float64")])
329+
def test_add_list_to_masked_array(self, val, dtype):
330+
# GH#22962
331+
ser = Series([1, None, 3], dtype="Int64")
332+
result = ser + [1, None, val]
333+
expected = Series([2, None, 3 + val], dtype=dtype)
334+
tm.assert_series_equal(result, expected)
335+
336+
result = [1, None, val] + ser
337+
tm.assert_series_equal(result, expected)
338+
339+
def test_add_list_to_masked_array_boolean(self):
340+
# GH#22962
341+
ser = Series([True, None, False], dtype="boolean")
342+
result = ser + [True, None, True]
343+
expected = Series([True, None, True], dtype="boolean")
344+
tm.assert_series_equal(result, expected)
345+
346+
result = [True, None, True] + ser
347+
tm.assert_series_equal(result, expected)
348+
328349

329350
# ------------------------------------------------------------------
330351
# Comparisons

0 commit comments

Comments
 (0)