Skip to content

Commit 7fba69d

Browse files
committed
ENH: Refactor roll_var to follow roll_cov structure
1 parent a85ce50 commit 7fba69d

File tree

1 file changed

+17
-51
lines changed

1 file changed

+17
-51
lines changed

Diff for: pandas/algos.pyx

+17-51
Original file line numberDiff line numberDiff line change
@@ -1284,10 +1284,8 @@ def roll_cov(ndarray[double_t] x, ndarray[double_t] y, int win, int minp,
12841284

12851285
if val_not_nan:
12861286
# Adding one observation...
1287-
nobs += 1
12881287
if prev_not_nan:
12891288
# ...and removing another
1290-
nobs -= 1
12911289
delta_x = val_x - prev_x
12921290
prev_x -= mean_x
12931291
mean_x += delta_x / nobs
@@ -1299,6 +1297,7 @@ def roll_cov(ndarray[double_t] x, ndarray[double_t] y, int win, int minp,
12991297
proddm_xy += (delta_x * (val_y + prev_y) + delta_y * (val_x + prev_x)) / 2
13001298
else:
13011299
# ...and not removing any
1300+
nobs += 1
13021301
delta_x = val_x - mean_x
13031302
mean_x += delta_x / nobs
13041303
delta_y = val_y - mean_y
@@ -1335,84 +1334,51 @@ def roll_var(ndarray[double_t] input, int win, int minp, int ddof=1):
13351334
"""
13361335
Numerically stable implementation using Welford's method.
13371336
"""
1338-
cdef double val, prev, mean_x = 0, ssqdm_x = 0, nobs = 0, delta
1337+
cdef double val, prev, mean_x = 0, ssqdm_x = 0, nobs = 0, delta, out
13391338
cdef Py_ssize_t i
13401339
cdef Py_ssize_t N = len(input)
13411340

13421341
cdef ndarray[double_t] output = np.empty(N, dtype=float)
13431342

13441343
minp = _check_minp(win, minp, N)
13451344

1346-
# Check for windows larger than array, addresses #7297
1347-
win = min(win, N)
1348-
1349-
# Over the first window, observations can only be added, never removed
1350-
for i from 0 <= i < win:
1351-
val = input[i]
1352-
1353-
# Not NaN
1354-
if val == val:
1355-
nobs += 1
1356-
delta = (val - mean_x)
1357-
mean_x += delta / nobs
1358-
ssqdm_x += delta * (val - mean_x)
1359-
1360-
if (nobs >= minp) and (nobs > ddof):
1361-
#pathological case
1362-
if nobs == 1:
1363-
val = 0
1364-
else:
1365-
val = ssqdm_x / (nobs - ddof)
1366-
if val < 0:
1367-
val = 0
1368-
else:
1369-
val = NaN
1370-
1371-
output[i] = val
1372-
1373-
# After the first window, observations can both be added and removed
1374-
for i from win <= i < N:
1345+
for i from 0 <= i < N:
13751346
val = input[i]
1376-
prev = input[i - win]
1347+
prev = NaN if i < win else input[i - win]
13771348

13781349
if val == val:
1350+
# Adding one observation...
13791351
if prev == prev:
1380-
# Adding one observation and removing another one
1381-
delta = val - prev
1352+
# ...and removing another
1353+
delta val - prev
13821354
prev -= mean_x
13831355
mean_x += delta / nobs
13841356
val -= mean_x
13851357
ssqdm_x += (val + prev) * delta
13861358
else:
13871359
# Adding one observation and not removing any
13881360
nobs += 1
1389-
delta = (val - mean_x)
1361+
delta = val - mean_x
13901362
mean_x += delta / nobs
13911363
ssqdm_x += delta * (val - mean_x)
13921364
elif prev == prev:
1393-
# Adding no new observation, but removing one
1365+
# adding no new observation, but removing one
13941366
nobs -= 1
13951367
if nobs:
1396-
delta = (prev - mean_x)
1397-
mean_x -= delta / nobs
1368+
delta = prev - mean_x
1369+
mean_x -= delta / nobs
13981370
ssqdm_x -= delta * (prev - mean_x)
13991371
else:
1400-
mean_x = 0
1401-
ssqdm_x = 0
1372+
mean_x = ssqdm_x = 0
14021373
# Variance is unchanged if no observation is added or removed
14031374

1404-
if (nobs >= minp) and (nobs > ddof):
1405-
#pathological case
1406-
if nobs == 1:
1407-
val = 0
1408-
else:
1409-
val = ssqdm_x / (nobs - ddof)
1410-
if val < 0:
1411-
val = 0
1375+
if nobs >= minp and nobs > ddof:
1376+
out = ssqdm_x / (nobs - ddof)
1377+
out = 0 if out < 0 else out
14121378
else:
1413-
val = NaN
1379+
out = NaN
14141380

1415-
output[i] = val
1381+
output[i] = out
14161382

14171383
return output
14181384

0 commit comments

Comments
 (0)