diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 7a10447e3ad40..76aadd2c97b67 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -187,7 +187,7 @@ Reshaping Sparse ^^^^^^ - +- Bug in :class:`SparseDataFrame` arithmetic operations incorrectly casting inputs to float (:issue:`28107`) - - diff --git a/pandas/core/sparse/frame.py b/pandas/core/sparse/frame.py index 8fe6850c84b8b..3d6ba0b8d9774 100644 --- a/pandas/core/sparse/frame.py +++ b/pandas/core/sparse/frame.py @@ -576,8 +576,8 @@ def _combine_match_index(self, other, func, level=None): this, other = self.align(other, join="outer", axis=0, level=level, copy=False) new_data = {} - for col, series in this.items(): - new_data[col] = func(series.values, other.values) + for col in this.columns: + new_data[col] = func(this[col], other) fill_value = self._get_op_result_fill_value(other, func) @@ -603,7 +603,7 @@ def _combine_match_columns(self, other, func, level=None): new_data = {} for col in left.columns: - new_data[col] = func(left[col], float(right[col])) + new_data[col] = func(left[col], right[col]) return self._constructor( new_data, diff --git a/pandas/tests/sparse/frame/test_frame.py b/pandas/tests/sparse/frame/test_frame.py index ddb50e0897a86..e372e2563e682 100644 --- a/pandas/tests/sparse/frame/test_frame.py +++ b/pandas/tests/sparse/frame/test_frame.py @@ -1487,6 +1487,22 @@ def test_comparison_op_scalar(self): assert isinstance(res, pd.SparseDataFrame) tm.assert_frame_equal(res.to_dense(), df != 0) + def test_add_series_retains_dtype(self): + # SparseDataFrame._combine_match_columns used to incorrectly cast + # to float + d = {0: [2j, 3j], 1: [0, 1]} + sdf = SparseDataFrame(data=d, default_fill_value=1) + result = sdf + sdf[0] + + df = sdf.to_dense() + expected = df + df[0] + tm.assert_frame_equal(result.to_dense(), expected) + + # Make it explicit to be on the safe side + edata = {0: [4j, 5j], 1: [3j, 1 + 3j]} + expected = DataFrame(edata) + tm.assert_frame_equal(result.to_dense(), expected) + @pytest.mark.filterwarnings("ignore:Sparse:FutureWarning") @pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")