library(roll)
library(microbenchmark)
options(microbenchmark.unit = "us")Usage
n_vars <- 10
n_obs <- 1000
weights <- 0.9 ^ (n_obs:1)
x <- matrix(rnorm(n_obs * n_vars), nrow = n_obs, ncol = n_vars)
y <- matrix(rnorm(n_obs), nrow = n_obs, ncol = 1)
x_lgl <- x < 0Rolling any
result <- microbenchmark("125" = roll_any(x_lgl, width = 125, min_obs = 1),
"250" = roll_any(x_lgl, width = 250, min_obs = 1),
"500" = roll_any(x_lgl, width = 500, min_obs = 1),
"1000" = roll_any(x_lgl, width = 1000, min_obs = 1))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 89.9 143.60 158.607 155.50 172.30 218.2 100
250 117.5 139.65 153.598 149.80 162.70 210.3 100
500 105.7 141.20 164.751 154.10 167.25 1000.0 100
1000 83.0 126.95 142.486 135.75 155.55 219.8 100
Rolling all
result <- microbenchmark("125" = roll_all(x_lgl, width = 125, min_obs = 1),
"250" = roll_all(x_lgl, width = 250, min_obs = 1),
"500" = roll_all(x_lgl, width = 500, min_obs = 1),
"1000" = roll_all(x_lgl, width = 1000, min_obs = 1))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 83.3 92.50 105.384 95.85 101.65 181.5 100
250 84.0 89.60 105.699 93.75 106.25 200.2 100
500 78.0 87.20 104.185 90.90 109.25 284.4 100
1000 74.3 80.35 89.024 82.40 88.40 177.2 100
Rolling sums
\[ \begin{aligned} &\text{Expanding window} \\ &\bullet\text{sum}_{x}\leftarrow\lambda\times\text{sum}_{x}+\text{w}_{new}\times\text{x}_{new}\\ &\text{Rolling window}\\ &\bullet\text{sum}_{x}\leftarrow\lambda\times\text{sum}_{x}+\text{w}_{new}\times\text{x}_{new}-\lambda\times\text{w}_{old}\times\text{x}_{old} \end{aligned} \]
result <- microbenchmark("125" = roll_sum(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_sum(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_sum(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_sum(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 92.3 105.80 130.447 116.80 144.75 253.3 100
250 95.0 104.85 126.861 113.35 137.15 273.7 100
500 91.7 102.65 123.558 111.90 130.20 286.9 100
1000 88.5 99.10 123.163 107.45 140.50 227.8 100
Rolling products
\[ \begin{aligned} &\text{Expanding window}\\ &\bullet\text{prod}_{w}\leftarrow\text{prod}_{w}\times\text{w}_{new}\\ &\bullet\text{prod}_{x}\leftarrow\text{prod}_{x}\times\text{x}_{new}\\ &\text{Rolling window}\\ &\bullet\text{prod}_{x}\leftarrow\text{prod}_{x}\times\text{x}_{new}/\text{x}_{old} \end{aligned} \]
result <- microbenchmark("125" = roll_prod(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_prod(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_prod(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_prod(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 204.7 219.35 241.780 234.20 246.50 387.8 100
250 207.3 221.75 253.678 234.35 259.70 610.5 100
500 139.8 152.10 173.136 167.15 185.20 266.8 100
1000 135.7 148.45 166.439 162.10 174.35 271.4 100
Rolling means
\[ \begin{aligned} &\text{Expanding window}\\ &\bullet\text{sum}_{w}\leftarrow\text{sum}_{w}+\text{w}_{new}\\ &\bullet\text{sum}_{x}\leftarrow\lambda\times\text{sum}_{x}+\text{w}_{new}\times\text{x}_{new}\\ &\text{Rolling window}\\ &\bullet\text{sum}_{x}\leftarrow\lambda\times\text{sum}_{x}+\text{w}_{new}\times\text{x}_{new}-\lambda\times\text{w}_{old}\times \text{x}_{old} \end{aligned} \]
result <- microbenchmark("125" = roll_mean(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_mean(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_mean(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_mean(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 93.0 109.80 129.285 116.10 152.35 216.7 100
250 101.5 110.35 132.540 118.95 151.65 355.6 100
500 96.0 108.40 130.634 115.35 153.00 232.8 100
1000 92.0 102.25 124.633 112.05 147.90 232.1 100
Rolling minimums
result <- microbenchmark("125" = roll_min(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_min(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_min(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_min(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 106.2 116.80 139.655 124.25 145.55 231.4 100
250 101.6 115.55 139.389 123.45 157.75 240.4 100
500 102.6 113.20 136.138 124.00 133.10 301.6 100
1000 103.2 116.55 137.804 128.15 154.25 227.3 100
Rolling maximums
result <- microbenchmark("125" = roll_max(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_max(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_max(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_max(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 104.9 123.35 155.302 140.35 180.35 287.7 100
250 106.4 123.60 157.260 137.30 188.45 309.5 100
500 108.3 123.25 151.723 131.10 170.30 415.7 100
1000 107.7 122.50 160.164 143.10 190.95 341.3 100
Rolling index of minimums
result <- microbenchmark("125" = roll_idxmin(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_idxmin(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_idxmin(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_idxmin(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 103.0 133.35 164.849 158.10 189.80 375.4 100
250 104.4 132.20 160.987 160.90 181.05 306.5 100
500 104.3 125.25 159.586 151.00 180.95 348.4 100
1000 94.6 131.20 158.884 156.75 180.40 365.6 100
Rolling index of maximums
result <- microbenchmark("125" = roll_idxmax(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_idxmax(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_idxmax(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_idxmax(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 108.1 128.95 158.456 149.75 180.05 310.0 100
250 102.0 130.25 154.937 151.95 170.40 278.5 100
500 106.6 121.95 149.305 141.75 174.35 243.6 100
1000 102.9 119.20 144.368 138.60 159.90 244.5 100
Rolling medians
# "'online' is only supported for equal 'weights'"
result <- microbenchmark("125" = roll_median(x, width = 125, min_obs = 1),
"250" = roll_median(x, width = 250, min_obs = 1),
"500" = roll_median(x, width = 500, min_obs = 1),
"1000" = roll_median(x, width = 1000, min_obs = 1))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 772.5 807.95 833.559 831.10 845.40 1283.9 100
250 749.9 803.20 817.830 817.35 833.55 871.3 100
500 719.1 746.15 864.045 766.05 784.65 5572.8 100
1000 544.9 567.45 615.572 584.50 603.45 2154.4 100
Rolling quantiles
# "'online' is only supported for equal 'weights'"
result <- microbenchmark("125" = roll_quantile(x, width = 125, min_obs = 1),
"250" = roll_quantile(x, width = 250, min_obs = 1),
"500" = roll_quantile(x, width = 500, min_obs = 1),
"1000" = roll_quantile(x, width = 1000, min_obs = 1))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 879.4 896.85 924.384 915.75 944.15 1217.5 100
250 863.5 880.90 912.054 907.50 930.65 1039.5 100
500 799.9 817.65 847.926 844.05 865.90 993.8 100
1000 614.1 628.35 657.674 657.60 682.85 718.3 100
Rolling variances
\[ \begin{aligned} &\text{Expanding window}\\ &\bullet\text{sum}_{w}\leftarrow\text{sum}_{w}+\text{w}_{new}\\ &\bullet\text{sumsq}_{w}\leftarrow\text{sumsq}_{w}+\text{w}_{new}^{2}\\ &\bullet\text{sumsq}_{x}\leftarrow\lambda\times\text{sumsq}_{x}+\text{w}_{new}\times (\text{x}_{new}-\text{mean}_{x})(\text{x}_{new}-\text{mean}_{prev_x})\\ &\text{Rolling window}\\ &\bullet\text{sumsq}_{x}\leftarrow\lambda\times\text{sumsq}_{x}+\text{w}_{new}\times (\text{x}_{new}-\text{mean}_{x})(\text{x}_{new}-\text{mean}_{prev_x})-\\ &\lambda\times\text{w}_{old}\times (\text{x}_{old}-\text{mean}_{x})(\text{x}_{old}-\text{mean}_{prev_x}) \end{aligned} \]
result <- microbenchmark("125" = roll_var(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_var(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_var(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_var(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 118.9 138.75 147.525 146.55 153.25 239.9 100
250 114.7 136.15 152.035 145.30 157.50 310.6 100
500 113.0 135.45 145.732 142.10 149.70 396.2 100
1000 106.5 123.95 139.719 130.85 137.90 641.3 100
Rolling standard deviations
result <- microbenchmark("125" = roll_sd(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_sd(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_sd(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_sd(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 121.3 142.10 152.207 147.20 156.0 282.4 100
250 119.7 139.50 153.363 145.30 156.8 395.7 100
500 128.2 136.00 148.320 141.70 149.6 270.2 100
1000 109.7 130.95 140.115 136.65 143.7 287.5 100
Rolling scaling and centering
result <- microbenchmark("125" = roll_scale(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_scale(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_scale(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_scale(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 147.0 151.90 162.812 156.35 162.00 330.4 100
250 142.5 152.75 208.041 159.55 171.80 3517.7 100
500 140.3 149.00 164.837 156.00 165.75 321.4 100
1000 135.9 140.60 151.609 146.15 151.80 267.4 100
Rolling covariances
\[ \begin{aligned} &\text{Expanding window}\\ &\bullet\text{sum}_{w}\leftarrow\text{sum}_{w}+\text{w}_{new}\\ &\bullet\text{sumsq}_{w}\leftarrow\text{sumsq}_{w}+\text{w}_{new}^{2}\\ &\bullet\text{sumsq}_{xy}\leftarrow\lambda\times\text{sumsq}_{xy}+\text{w}_{new}\times (\text{x}_{new}-\text{mean}_{x})(\text{y}_{new}-\text{mean}_{prev_y})\\ &\text{Rolling window}\\ &\bullet\text{sumsq}_{xy}\leftarrow\lambda\times\text{sumsq}_{xy}+\text{w}_{new}\times (\text{x}_{new}-\text{mean}_{x})(\text{y}_{new}-\text{mean}_{prev_y})-\\ &\lambda\times\text{w}_{old}\times (\text{x}_{old}-\text{mean}_{x})(\text{y}_{old}-\text{mean}_{prev_y}) \end{aligned} \]
result <- microbenchmark("125" = roll_cov(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_cov(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_cov(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_cov(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 724.4 906.60 968.837 983.15 1018.15 1164.9 100
250 724.5 881.15 1045.220 942.70 990.00 6748.3 100
500 677.5 820.30 960.156 867.15 929.85 6220.2 100
1000 613.7 739.35 828.754 770.95 834.35 5979.7 100
Rolling correlations
result <- microbenchmark("125" = roll_cor(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_cor(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_cor(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_cor(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 862.8 1014.30 1093.189 1096.25 1165.60 1298.5 100
250 841.3 968.30 1121.754 1063.50 1115.20 4588.4 100
500 788.5 906.80 1027.385 986.30 1083.00 4503.5 100
1000 688.6 801.25 915.180 846.25 896.05 4321.1 100
Rolling crossproducts
result <- microbenchmark("125" = roll_crossprod(x, width = 125, min_obs = 1, weights = weights),
"250" = roll_crossprod(x, width = 250, min_obs = 1, weights = weights),
"500" = roll_crossprod(x, width = 500, min_obs = 1, weights = weights),
"1000" = roll_crossprod(x, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 595.0 651.5 713.679 710.20 767.80 875.7 100
250 592.1 637.3 727.521 690.80 748.55 4091.1 100
500 574.7 624.7 759.912 715.65 739.85 4138.6 100
1000 529.9 564.7 684.105 589.80 674.30 4107.4 100
Rolling linear models
\[ \begin{aligned} &\text{coef}=\text{cov}_{xx}^{-1}\times\text{cov}_{xy}\\ &\text{intercept}=\text{mean}_{y}-\text{coef}\times\text{mean}_{x}\\ &\text{rsq}=\frac{\text{coef}^{T}\times\text{cov}_{xx}\times\text{coef}}{\text{var}_{y}}\\ &\text{var}_{resid}=\frac{(1-\text{rsq})(\text{var}_{y})(\text{sum}_{w}-\text{sumsq}_{w}/\text{sum}_{w})}{\text{n}_{rows}-\text{n}_{cols}}\\ &\text{xx}=\text{cov}_{xx}\times(\text{sum}_{w}-\text{sumsq}_{w}/\text{sum}_{w})\\ &\text{se}_{coef}=\sqrt{\text{var}_{resid}\times\text{diag}(\text{xx}^{-1})}\\ &\text{se}_{intercept}=\sqrt{\text{var}_{resid}\left(1/\text{sum}_{w}+\text{mean}_{x}^{T}\text{xx}^{-1}\text{mean}_{x}\right)} \end{aligned} \]
result <- microbenchmark("125" = roll_lm(x, y, width = 125, min_obs = 1, weights = weights),
"250" = roll_lm(x, y, width = 250, min_obs = 1, weights = weights),
"500" = roll_lm(x, y, width = 500, min_obs = 1, weights = weights),
"1000" = roll_lm(x, y, width = 1000, min_obs = 1, weights = weights))
print(result)Unit: microseconds
expr min lq mean median uq max neval
125 2190.5 2401.40 2549.411 2498.90 2593.55 3943.7 100
250 2193.5 2334.05 2565.596 2493.55 2627.20 6566.8 100
500 2111.9 2338.05 2567.908 2428.40 2577.60 6740.5 100
1000 2037.4 2267.00 2533.283 2398.95 2546.65 6696.1 100
References
- Weights: https://stackoverflow.com/a/9933794
- Index: https://stackoverflow.com/a/11316626
- Index: https://stackoverflow.com/a/34363187
- Index: https://stackoverflow.com/a/243342
- Quantile (comparator): https://stackoverflow.com/a/51992954
- Quantile (comparator): https://stackoverflow.com/a/25921772
- Quantile (comparator): https://stackoverflow.com/a/40416506
- Median: https://stackoverflow.com/a/5970314
- Median: https://stackoverflow.com/a/5971248
- Median: https://gist.github.com/ashelly/5665911
- Standard errors: https://stats.stackexchange.com/a/64217