Backport PR #31529: BUG: Series multiplication with timedelta scalar … · pandas-dev/pandas@a8aff6c (original) (raw)
3 files changed
lines changed
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -44,6 +44,7 @@ Timezones | ||
| 44 | 44 | Numeric |
| 45 | 45 | ^^^^^^^ |
| 46 | 46 | - Bug in dtypes being lost in ``DataFrame.__invert__`` (``~`` operator) with mixed dtypes (:issue:`31183`) |
| 47 | +- Bug in :class:`Series` multiplication when multiplying a numeric :class:`Series` with >10000 elements with a timedelta-like scalar (:issue:`31467`) | |
| 47 | 48 | - |
| 48 | 49 | |
| 49 | 50 | Conversion |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,7 +8,7 @@ | ||
| 8 | 8 | |
| 9 | 9 | import numpy as np |
| 10 | 10 | |
| 11 | -from pandas._libs import Timestamp, lib, ops as libops | |
| 11 | +from pandas._libs import Timedelta, Timestamp, lib, ops as libops | |
| 12 | 12 | |
| 13 | 13 | from pandas.core.dtypes.cast import ( |
| 14 | 14 | construct_1d_object_array_from_listlike, |
| @@ -184,11 +184,12 @@ def arithmetic_op( | ||
| 184 | 184 | rvalues = maybe_upcast_for_op(rvalues, lvalues.shape) |
| 185 | 185 | |
| 186 | 186 | if should_extension_dispatch(left, rvalues) or isinstance( |
| 187 | -rvalues, (ABCTimedeltaArray, ABCDatetimeArray, Timestamp) | |
| 187 | +rvalues, (ABCTimedeltaArray, ABCDatetimeArray, Timestamp, Timedelta) | |
| 188 | 188 | ): |
| 189 | 189 | # TimedeltaArray, DatetimeArray, and Timestamp are included here |
| 190 | 190 | # because they have `freq` attribute which is handled correctly |
| 191 | 191 | # by dispatch_to_extension_op. |
| 192 | +# Timedelta is included because numexpr will fail on it, see GH#31457 | |
| 192 | 193 | res_values = dispatch_to_extension_op(op, lvalues, rvalues) |
| 193 | 194 | |
| 194 | 195 | else: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -176,6 +176,28 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box): | ||
| 176 | 176 | commute = scalar_td * index |
| 177 | 177 | tm.assert_equal(commute, expected) |
| 178 | 178 | |
| 179 | +@pytest.mark.parametrize( | |
| 180 | + "scalar_td", | |
| 181 | + [ | |
| 182 | + Timedelta(days=1), | |
| 183 | + Timedelta(days=1).to_timedelta64(), | |
| 184 | + Timedelta(days=1).to_pytimedelta(), | |
| 185 | + ], | |
| 186 | + ids=lambda x: type(x).__name__, | |
| 187 | + ) | |
| 188 | +def test_numeric_arr_mul_tdscalar_numexpr_path(self, scalar_td, box): | |
| 189 | +arr = np.arange(2 * 10 ** 4).astype(np.int64) | |
| 190 | +obj = tm.box_expected(arr, box, transpose=False) | |
| 191 | + | |
| 192 | +expected = arr.view("timedelta64[D]").astype("timedelta64[ns]") | |
| 193 | +expected = tm.box_expected(expected, box, transpose=False) | |
| 194 | + | |
| 195 | +result = obj * scalar_td | |
| 196 | +tm.assert_equal(result, expected) | |
| 197 | + | |
| 198 | +result = scalar_td * obj | |
| 199 | +tm.assert_equal(result, expected) | |
| 200 | + | |
| 179 | 201 | def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box): |
| 180 | 202 | index = numeric_idx[1:3] |
| 181 | 203 |