RollingIqr#
Description#
RollingIqr computes the rolling inter-quartile range:
A robust spread measure: discards the top and bottom 25% of the window, so it is unaffected by single-point outliers. Useful as the denominator of a robust z-score, or for outlier-resistant volatility heuristics.
Parameters: window_size (int, positive).
NaN handling: NaN values should be preprocessed.
NaN handling#
Policy: ignore. A NaN in any input at index t causes the function to skip that step: output at t is NaN and internal state is unchanged. Subsequent finite samples are processed as if step t had not occurred.
Examples#
Usage example#
import numpy as np
import pandas as pd
from screamer import RollingIqr
rng = np.random.default_rng(0)
x = rng.standard_normal(500)
iqr = RollingIqr(30)(x)
# Validate against pandas (post-warmup, to ~1e-12)
ref = (
pd.Series(x).rolling(30).quantile(0.75)
- pd.Series(x).rolling(30).quantile(0.25)
).to_numpy()
np.testing.assert_allclose(iqr[29:], ref[29:], atol=1e-12)
Implementation Details#
Algorithm#
A single OrderStatisticTree (the same primitive RollingQuantile uses) is queried twice per step -- once at the 0.25 * (n - 1) position and once at 0.75 * (n - 1) -- with linear interpolation between adjacent order statistics, identical to RollingQuantile's formula.
Why not just two RollingQuantile instances?#
Composing as RollingQuantile(w, 0.75)(x) - RollingQuantile(w, 0.25)(x) would work but use two independent OSTs. The dedicated implementation has:
Two |
|
|
|---|---|---|
Memory |
2 trees (≈ 2W nodes) |
1 tree (≈ W nodes) |
Inserts/erases per step |
2 + 2 |
1 + 1 |
Asymptotic complexity |
|
|
Same asymptotic complexity, half the memory and half the work per step. Validated in tests against the composition reference (post-warmup) to floating-point precision.
Complexity#
Time complexity:
O(log W)per step.Space complexity:
O(window_size).
Reference#
Equivalent to pandas.Series.rolling(w).quantile(0.75) - pandas.Series.rolling(w).quantile(0.25).