@@ -1473,66 +1473,9 @@ def roll_weighted_var(const float64_t[:] values, const float64_t[:] weights,
1473
1473
# ----------------------------------------------------------------------
1474
1474
# Exponentially weighted moving average
1475
1475
1476
- def ewma_time (const float64_t[:] vals , int64_t[:] start , int64_t[:] end ,
1477
- int minp , ndarray[int64_t] times , int64_t halflife ):
1478
- """
1479
- Compute exponentially-weighted moving average using halflife and time
1480
- distances.
1481
-
1482
- Parameters
1483
- ----------
1484
- vals : ndarray[float_64]
1485
- start: ndarray[int_64]
1486
- end: ndarray[int_64]
1487
- minp : int
1488
- times : ndarray[int64]
1489
- halflife : int64
1490
-
1491
- Returns
1492
- -------
1493
- ndarray
1494
- """
1495
- cdef:
1496
- Py_ssize_t i, j, num_not_nan = 0 , N = len (vals)
1497
- bint is_not_nan
1498
- float64_t last_result, weights_dot, weights_sum, weight, halflife_float
1499
- float64_t[:] times_float
1500
- float64_t[:] observations = np.zeros(N, dtype = float )
1501
- float64_t[:] times_masked = np.zeros(N, dtype = float )
1502
- ndarray[float64_t] output = np.empty(N, dtype = float )
1503
-
1504
- if N == 0 :
1505
- return output
1506
-
1507
- halflife_float = < float64_t> halflife
1508
- times_float = times.astype(float )
1509
- last_result = vals[0 ]
1510
-
1511
- with nogil:
1512
- for i in range (N):
1513
- is_not_nan = vals[i] == vals[i]
1514
- num_not_nan += is_not_nan
1515
- if is_not_nan:
1516
- times_masked[num_not_nan- 1 ] = times_float[i]
1517
- observations[num_not_nan- 1 ] = vals[i]
1518
-
1519
- weights_sum = 0
1520
- weights_dot = 0
1521
- for j in range (num_not_nan):
1522
- weight = 0.5 ** (
1523
- (times_float[i] - times_masked[j]) / halflife_float)
1524
- weights_sum += weight
1525
- weights_dot += weight * observations[j]
1526
-
1527
- last_result = weights_dot / weights_sum
1528
-
1529
- output[i] = last_result if num_not_nan >= minp else NaN
1530
-
1531
- return output
1532
-
1533
-
1534
1476
def ewma (float64_t[:] vals , int64_t[:] start , int64_t[:] end , int minp ,
1535
- float64_t com , bint adjust , bint ignore_na ):
1477
+ float64_t com , bint adjust , bint ignore_na , float64_t[:] times ,
1478
+ float64_t halflife ):
1536
1479
"""
1537
1480
Compute exponentially-weighted moving average using center-of-mass.
1538
1481
@@ -1555,13 +1498,15 @@ def ewma(float64_t[:] vals, int64_t[:] start, int64_t[:] end, int minp,
1555
1498
Py_ssize_t i, j, s, e, nobs, win_size, N = len (vals), M = len (start)
1556
1499
float64_t[:] sub_vals
1557
1500
ndarray[float64_t] sub_output, output = np.empty(N, dtype = float )
1558
- float64_t alpha, old_wt_factor, new_wt, weighted_avg, old_wt, cur
1501
+ float64_t alpha, old_wt_factor, new_wt, weighted_avg, old_wt, cur, delta
1559
1502
bint is_observation
1560
1503
1561
1504
if N == 0 :
1562
1505
return output
1563
1506
1564
1507
alpha = 1. / (1. + com)
1508
+ old_wt_factor = 1. - alpha
1509
+ new_wt = 1. if adjust else alpha
1565
1510
1566
1511
for j in range (M):
1567
1512
s = start[j]
@@ -1570,9 +1515,6 @@ def ewma(float64_t[:] vals, int64_t[:] start, int64_t[:] end, int minp,
1570
1515
win_size = len (sub_vals)
1571
1516
sub_output = np.empty(win_size, dtype = float )
1572
1517
1573
- old_wt_factor = 1. - alpha
1574
- new_wt = 1. if adjust else alpha
1575
-
1576
1518
weighted_avg = sub_vals[0 ]
1577
1519
is_observation = weighted_avg == weighted_avg
1578
1520
nobs = int (is_observation)
@@ -1587,8 +1529,8 @@ def ewma(float64_t[:] vals, int64_t[:] start, int64_t[:] end, int minp,
1587
1529
if weighted_avg == weighted_avg:
1588
1530
1589
1531
if is_observation or not ignore_na:
1590
-
1591
- old_wt *= old_wt_factor
1532
+ delta = times[i] - times[i - 1 ]
1533
+ old_wt *= old_wt_factor ** (delta / halflife)
1592
1534
if is_observation:
1593
1535
1594
1536
# avoid numerical errors on constant series
0 commit comments