Skip to content

Commit 7f9074a

Browse files
Backport PR #43052: REGR: window ewm slowdown (#43069)
Co-authored-by: Matthew Zeitlin <[email protected]>
1 parent 1e9de6b commit 7f9074a

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

doc/source/whatsnew/v1.3.3.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ including other versions of pandas.
1414

1515
Fixed regressions
1616
~~~~~~~~~~~~~~~~~
17+
- Performance regression in :meth:`core.window.ewm.ExponentialMovingWindow.mean` (:issue:`42333`)
1718
-
1819
-
1920

pandas/_libs/window/aggregations.pyx

+14-6
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,7 @@ def roll_weighted_var(const float64_t[:] values, const float64_t[:] weights,
14861486

14871487
def ewma(const float64_t[:] vals, const int64_t[:] start, const int64_t[:] end,
14881488
int minp, float64_t com, bint adjust, bint ignore_na,
1489-
const float64_t[:] deltas) -> np.ndarray:
1489+
const float64_t[:] deltas=None) -> np.ndarray:
14901490
"""
14911491
Compute exponentially-weighted moving average using center-of-mass.
14921492

@@ -1499,7 +1499,8 @@ def ewma(const float64_t[:] vals, const int64_t[:] start, const int64_t[:] end,
14991499
com : float64
15001500
adjust : bool
15011501
ignore_na : bool
1502-
deltas : ndarray (float64 type)
1502+
deltas : ndarray (float64 type), optional. If None, implicitly assumes equally
1503+
spaced points (used when `times` is not passed)
15031504

15041505
Returns
15051506
-------
@@ -1508,14 +1509,17 @@ def ewma(const float64_t[:] vals, const int64_t[:] start, const int64_t[:] end,
15081509

15091510
cdef:
15101511
Py_ssize_t i, j, s, e, nobs, win_size, N = len(vals), M = len(start)
1511-
const float64_t[:] sub_deltas, sub_vals
1512+
const float64_t[:] sub_vals
1513+
const float64_t[:] sub_deltas=None
15121514
ndarray[float64_t] sub_output, output = np.empty(N, dtype=np.float64)
15131515
float64_t alpha, old_wt_factor, new_wt, weighted_avg, old_wt, cur
1514-
bint is_observation
1516+
bint is_observation, use_deltas
15151517

15161518
if N == 0:
15171519
return output
15181520

1521+
use_deltas = deltas is not None
1522+
15191523
alpha = 1. / (1. + com)
15201524
old_wt_factor = 1. - alpha
15211525
new_wt = 1. if adjust else alpha
@@ -1526,7 +1530,8 @@ def ewma(const float64_t[:] vals, const int64_t[:] start, const int64_t[:] end,
15261530
sub_vals = vals[s:e]
15271531
# note that len(deltas) = len(vals) - 1 and deltas[i] is to be used in
15281532
# conjunction with vals[i+1]
1529-
sub_deltas = deltas[s:e - 1]
1533+
if use_deltas:
1534+
sub_deltas = deltas[s:e - 1]
15301535
win_size = len(sub_vals)
15311536
sub_output = np.empty(win_size, dtype=np.float64)
15321537

@@ -1544,7 +1549,10 @@ def ewma(const float64_t[:] vals, const int64_t[:] start, const int64_t[:] end,
15441549
if weighted_avg == weighted_avg:
15451550

15461551
if is_observation or not ignore_na:
1547-
old_wt *= old_wt_factor ** sub_deltas[i - 1]
1552+
if use_deltas:
1553+
old_wt *= old_wt_factor ** sub_deltas[i - 1]
1554+
else:
1555+
old_wt *= old_wt_factor
15481556
if is_observation:
15491557

15501558
# avoid numerical errors on constant series

pandas/core/window/ewm.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,14 @@ def mean(self, *args, engine=None, engine_kwargs=None, **kwargs):
448448
if engine_kwargs is not None:
449449
raise ValueError("cython engine does not accept engine_kwargs")
450450
nv.validate_window_func("mean", args, kwargs)
451+
452+
deltas = None if self.times is None else self._deltas
451453
window_func = partial(
452454
window_aggregations.ewma,
453455
com=self._com,
454456
adjust=self.adjust,
455457
ignore_na=self.ignore_na,
456-
deltas=self._deltas,
458+
deltas=deltas,
457459
)
458460
return self._apply(window_func)
459461
else:

0 commit comments

Comments
 (0)