diff --git a/doc/source/whatsnew/v1.0.1.rst b/doc/source/whatsnew/v1.0.1.rst index 95fab6a18ffe1..df001bc18b0a0 100644 --- a/doc/source/whatsnew/v1.0.1.rst +++ b/doc/source/whatsnew/v1.0.1.rst @@ -44,6 +44,7 @@ Timezones Numeric ^^^^^^^ - Bug in dtypes being lost in ``DataFrame.__invert__`` (``~`` operator) with mixed dtypes (:issue:`31183`) +- Bug in :class:`Series` multiplication when multiplying a numeric :class:`Series` with >10000 elements with a timedelta-like scalar (:issue:`31467`) - Conversion diff --git a/pandas/core/ops/array_ops.py b/pandas/core/ops/array_ops.py index b84d468fff736..56519846c702d 100644 --- a/pandas/core/ops/array_ops.py +++ b/pandas/core/ops/array_ops.py @@ -8,7 +8,7 @@ import numpy as np -from pandas._libs import Timestamp, lib, ops as libops +from pandas._libs import Timedelta, Timestamp, lib, ops as libops from pandas.core.dtypes.cast import ( construct_1d_object_array_from_listlike, @@ -184,11 +184,12 @@ def arithmetic_op( rvalues = maybe_upcast_for_op(rvalues, lvalues.shape) if should_extension_dispatch(left, rvalues) or isinstance( - rvalues, (ABCTimedeltaArray, ABCDatetimeArray, Timestamp) + rvalues, (ABCTimedeltaArray, ABCDatetimeArray, Timestamp, Timedelta) ): # TimedeltaArray, DatetimeArray, and Timestamp are included here # because they have `freq` attribute which is handled correctly # by dispatch_to_extension_op. + # Timedelta is included because numexpr will fail on it, see GH#31457 res_values = dispatch_to_extension_op(op, lvalues, rvalues) else: diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index f55e2b98ee912..22da3de80e196 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -176,6 +176,28 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box): commute = scalar_td * index tm.assert_equal(commute, expected) + @pytest.mark.parametrize( + "scalar_td", + [ + Timedelta(days=1), + Timedelta(days=1).to_timedelta64(), + Timedelta(days=1).to_pytimedelta(), + ], + ids=lambda x: type(x).__name__, + ) + def test_numeric_arr_mul_tdscalar_numexpr_path(self, scalar_td, box): + arr = np.arange(2 * 10 ** 4).astype(np.int64) + obj = tm.box_expected(arr, box, transpose=False) + + expected = arr.view("timedelta64[D]").astype("timedelta64[ns]") + expected = tm.box_expected(expected, box, transpose=False) + + result = obj * scalar_td + tm.assert_equal(result, expected) + + result = scalar_td * obj + tm.assert_equal(result, expected) + def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box): index = numeric_idx[1:3]