slidify
returns a rolling (sliding) version of the input function, with a
rolling (sliding) .period
specified by the user.
Usage
slidify(
.f,
.period = 1,
.align = c("center", "left", "right"),
.partial = FALSE,
.unlist = TRUE
)
Arguments
- .f
A function, formula, or vector (not necessarily atomic).
If a function, it is used as is.
If a formula, e.g.
~ .x + 2
, it is converted to a function. No longer recommended.If character vector, numeric vector, or list, it is converted to an extractor function. Character vectors index by name and numeric vectors index by position; use a list to index by position and name at different levels. If a component is not present, the value of
.default
will be returned.- .period
The period size to roll over
- .align
One of "center", "left" or "right".
- .partial
Should the moving window be allowed to return partial (incomplete) windows instead of
NA
values. Set toFALSE
by default, but can be switched toTRUE
to removeNA
's.- .unlist
If the function returns a single value each time it is called, use
.unlist = TRUE
. If the function returns more than one value, or a more complicated object (like a linear model), use.unlist = FALSE
to create a list-column of the rolling results.
Details
The slidify()
function is almost identical to tibbletime::rollify()
with 3 improvements:
Alignment ("center", "left", "right")
Partial windows are allowed
Uses
slider
under the hood, which improves speed and reliability by implementing code at C++ level
Make any function a Sliding (Rolling) Function
slidify()
turns a function into a sliding version
of itself for use inside of a call to dplyr::mutate()
, however it works
equally as well when called from purrr::map()
.
Because of it's intended use with dplyr::mutate()
, slidify
creates a function that always returns output with the same length of the
input
Alignment
Rolling / Sliding functions generate .period - 1
fewer values than the incoming vector.
Thus, the vector needs to be aligned. Alignment of the vector follows 3 types:
center (default):
NA
or.partial
values are divided and added to the beginning and end of the series to "Center" the moving average. This is common in Time Series applications (e.g. denoising).left:
NA
or.partial
values are added to the end to shift the series to the Left.right:
NA
or.partial
values are added to the beginning to shift the series to the Right. This is common in Financial Applications (e.g moving average cross-overs).
Allowing Partial Windows
A key improvement over tibbletime::slidify()
is that timetk::slidify()
implements
.partial
rolling windows. Just set .partial = TRUE
.
References
The Tibbletime R Package by Davis Vaughan, which includes the original
rollify()
Function
See also
Transformation Functions:
slidify_vec()
- A simple vectorized function for applying summary functions to rolling windows.
Augmentation Functions (Add Rolling Multiple Columns):
tk_augment_slidify()
- For easily adding multiple rolling windows to you data
Slider R Package:
slider::pslide()
- The workhorse function that powerstimetk::slidify()
Examples
library(dplyr)
FB <- FANG %>% dplyr::filter(symbol == "FB")
# --- ROLLING MEAN (SINGLE ARG EXAMPLE) ---
# Turn the normal mean function into a rolling mean with a 5 row .period
mean_roll_5 <- slidify(mean, .period = 5, .align = "right")
FB %>%
mutate(rolling_mean_5 = mean_roll_5(adjusted))
#> # A tibble: 1,008 × 9
#> symbol date open high low close volume adjusted rolling_mean_5
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 27.4 28.2 27.4 28 69846400 28 NA
#> 2 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 NA
#> 3 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 NA
#> 4 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 NA
#> 5 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 28.6
#> 6 FB 2013-01-09 29.7 30.6 29.5 30.6 104787700 30.6 29.1
#> 7 FB 2013-01-10 30.6 31.5 30.3 31.3 95316400 31.3 29.8
#> 8 FB 2013-01-11 31.3 32.0 31.1 31.7 89598000 31.7 30.4
#> 9 FB 2013-01-14 32.1 32.2 30.6 31.0 98892800 31.0 30.7
#> 10 FB 2013-01-15 30.6 31.7 29.9 30.1 173242600 30.1 30.9
#> # ℹ 998 more rows
# Use `partial = TRUE` to allow partial windows (those with less than the full .period)
mean_roll_5_partial <- slidify(mean, .period = 5, .align = "right", .partial = TRUE)
FB %>%
mutate(rolling_mean_5 = mean_roll_5_partial(adjusted))
#> # A tibble: 1,008 × 9
#> symbol date open high low close volume adjusted rolling_mean_5
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 27.4 28.2 27.4 28 69846400 28 28
#> 2 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 27.9
#> 3 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 28.2
#> 4 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 28.5
#> 5 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 28.6
#> 6 FB 2013-01-09 29.7 30.6 29.5 30.6 104787700 30.6 29.1
#> 7 FB 2013-01-10 30.6 31.5 30.3 31.3 95316400 31.3 29.8
#> 8 FB 2013-01-11 31.3 32.0 31.1 31.7 89598000 31.7 30.4
#> 9 FB 2013-01-14 32.1 32.2 30.6 31.0 98892800 31.0 30.7
#> 10 FB 2013-01-15 30.6 31.7 29.9 30.1 173242600 30.1 30.9
#> # ℹ 998 more rows
# There's nothing stopping you from combining multiple rolling functions with
# different .period sizes in the same mutate call
mean_roll_10 <- slidify(mean, .period = 10, .align = "right")
FB %>%
select(symbol, date, adjusted) %>%
mutate(
rolling_mean_5 = mean_roll_5(adjusted),
rolling_mean_10 = mean_roll_10(adjusted)
)
#> # A tibble: 1,008 × 5
#> symbol date adjusted rolling_mean_5 rolling_mean_10
#> <chr> <date> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 28 NA NA
#> 2 FB 2013-01-03 27.8 NA NA
#> 3 FB 2013-01-04 28.8 NA NA
#> 4 FB 2013-01-07 29.4 NA NA
#> 5 FB 2013-01-08 29.1 28.6 NA
#> 6 FB 2013-01-09 30.6 29.1 NA
#> 7 FB 2013-01-10 31.3 29.8 NA
#> 8 FB 2013-01-11 31.7 30.4 NA
#> 9 FB 2013-01-14 31.0 30.7 NA
#> 10 FB 2013-01-15 30.1 30.9 29.8
#> # ℹ 998 more rows
# For summary operations like rolling means, we can accomplish large-scale
# multi-rolls with tk_augment_slidify()
FB %>%
select(symbol, date, adjusted) %>%
tk_augment_slidify(
adjusted, .period = 5:10, .f = mean, .align = "right",
.names = stringr::str_c("MA_", 5:10)
)
#> # A tibble: 1,008 × 9
#> symbol date adjusted MA_5 MA_6 MA_7 MA_8 MA_9 MA_10
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 28 NA NA NA NA NA NA
#> 2 FB 2013-01-03 27.8 NA NA NA NA NA NA
#> 3 FB 2013-01-04 28.8 NA NA NA NA NA NA
#> 4 FB 2013-01-07 29.4 NA NA NA NA NA NA
#> 5 FB 2013-01-08 29.1 28.6 NA NA NA NA NA
#> 6 FB 2013-01-09 30.6 29.1 28.9 NA NA NA NA
#> 7 FB 2013-01-10 31.3 29.8 29.5 29.3 NA NA NA
#> 8 FB 2013-01-11 31.7 30.4 30.1 29.8 29.6 NA NA
#> 9 FB 2013-01-14 31.0 30.7 30.5 30.3 29.9 29.7 NA
#> 10 FB 2013-01-15 30.1 30.9 30.6 30.4 30.2 30.0 29.8
#> # ℹ 998 more rows
# --- GROUPS AND ROLLING ----
# One of the most powerful things about this is that it works with
# groups since `mutate` is being used
mean_roll_3 <- slidify(mean, .period = 3, .align = "right")
FANG %>%
group_by(symbol) %>%
mutate(mean_roll = mean_roll_3(adjusted)) %>%
slice(1:5)
#> # A tibble: 20 × 9
#> # Groups: symbol [4]
#> symbol date open high low close volume adjusted mean_roll
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 AMZN 2013-01-02 256. 258. 253. 257. 3271000 257. NA
#> 2 AMZN 2013-01-03 257. 261. 256. 258. 2750900 258. NA
#> 3 AMZN 2013-01-04 258. 260. 257. 259. 1874200 259. 258.
#> 4 AMZN 2013-01-07 263. 270. 263. 268. 4910000 268. 262.
#> 5 AMZN 2013-01-08 267. 269. 264. 266. 3010700 266. 265.
#> 6 FB 2013-01-02 27.4 28.2 27.4 28 69846400 28 NA
#> 7 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 NA
#> 8 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 28.2
#> 9 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 28.6
#> 10 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 29.1
#> 11 GOOG 2013-01-02 719. 727. 717. 723. 5101500 361. NA
#> 12 GOOG 2013-01-03 725. 732. 721. 724. 4653700 361. NA
#> 13 GOOG 2013-01-04 729. 741. 728. 738. 5547600 369. 364.
#> 14 GOOG 2013-01-07 735. 739. 731. 735. 3323800 367. 366.
#> 15 GOOG 2013-01-08 736. 736. 724. 733. 3364700 366. 367.
#> 16 NFLX 2013-01-02 95.2 95.8 90.7 92.0 19431300 13.1 NA
#> 17 NFLX 2013-01-03 92.0 97.9 91.5 96.6 27912500 13.8 NA
#> 18 NFLX 2013-01-04 96.5 97.7 95.5 96.0 17761100 13.7 13.6
#> 19 NFLX 2013-01-07 96.4 102. 96.1 99.2 45550400 14.2 13.9
#> 20 NFLX 2013-01-08 100. 101. 96.8 97.2 24714900 13.9 13.9
# --- ROLLING CORRELATION (MULTIPLE ARG EXAMPLE) ---
# With 2 args, use the purrr syntax of ~ and .x, .y
# Rolling correlation example
cor_roll <- slidify(~cor(.x, .y), .period = 5, .align = "right")
FB %>%
mutate(running_cor = cor_roll(adjusted, open))
#> # A tibble: 1,008 × 9
#> symbol date open high low close volume adjusted running_cor
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 27.4 28.2 27.4 28 69846400 28 NA
#> 2 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 NA
#> 3 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 NA
#> 4 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 NA
#> 5 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 0.749
#> 6 FB 2013-01-09 29.7 30.6 29.5 30.6 104787700 30.6 0.805
#> 7 FB 2013-01-10 30.6 31.5 30.3 31.3 95316400 31.3 0.859
#> 8 FB 2013-01-11 31.3 32.0 31.1 31.7 89598000 31.7 0.884
#> 9 FB 2013-01-14 32.1 32.2 30.6 31.0 98892800 31.0 0.667
#> 10 FB 2013-01-15 30.6 31.7 29.9 30.1 173242600 30.1 0.379
#> # ℹ 998 more rows
# With >2 args, create an anonymous function with >2 args or use
# the purrr convention of ..1, ..2, ..3 to refer to the arguments
avg_of_avgs <- slidify(
function(x, y, z) (mean(x) + mean(y) + mean(z)) / 3,
.period = 10,
.align = "right"
)
# Or
avg_of_avgs <- slidify(
~(mean(..1) + mean(..2) + mean(..3)) / 3,
.period = 10,
.align = "right"
)
FB %>%
mutate(avg_of_avgs = avg_of_avgs(open, high, low))
#> # A tibble: 1,008 × 9
#> symbol date open high low close volume adjusted avg_of_avgs
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 27.4 28.2 27.4 28 69846400 28 NA
#> 2 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 NA
#> 3 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 NA
#> 4 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 NA
#> 5 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 NA
#> 6 FB 2013-01-09 29.7 30.6 29.5 30.6 104787700 30.6 NA
#> 7 FB 2013-01-10 30.6 31.5 30.3 31.3 95316400 31.3 NA
#> 8 FB 2013-01-11 31.3 32.0 31.1 31.7 89598000 31.7 NA
#> 9 FB 2013-01-14 32.1 32.2 30.6 31.0 98892800 31.0 NA
#> 10 FB 2013-01-15 30.6 31.7 29.9 30.1 173242600 30.1 29.7
#> # ℹ 998 more rows
# Optional arguments MUST be passed at the creation of the rolling function
# Only data arguments that are "rolled over" are allowed when calling the
# rolling version of the function
FB$adjusted[1] <- NA
roll_mean_na_rm <- slidify(~mean(.x, na.rm = TRUE), .period = 5, .align = "right")
FB %>%
mutate(roll_mean = roll_mean_na_rm(adjusted))
#> # A tibble: 1,008 × 9
#> symbol date open high low close volume adjusted roll_mean
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-01-02 27.4 28.2 27.4 28 69846400 NA NA
#> 2 FB 2013-01-03 27.9 28.5 27.6 27.8 63140600 27.8 NA
#> 3 FB 2013-01-04 28.0 28.9 27.8 28.8 72715400 28.8 NA
#> 4 FB 2013-01-07 28.7 29.8 28.6 29.4 83781800 29.4 NA
#> 5 FB 2013-01-08 29.5 29.6 28.9 29.1 45871300 29.1 28.8
#> 6 FB 2013-01-09 29.7 30.6 29.5 30.6 104787700 30.6 29.1
#> 7 FB 2013-01-10 30.6 31.5 30.3 31.3 95316400 31.3 29.8
#> 8 FB 2013-01-11 31.3 32.0 31.1 31.7 89598000 31.7 30.4
#> 9 FB 2013-01-14 32.1 32.2 30.6 31.0 98892800 31.0 30.7
#> 10 FB 2013-01-15 30.6 31.7 29.9 30.1 173242600 30.1 30.9
#> # ℹ 998 more rows
# --- ROLLING REGRESSIONS ----
# Rolling regressions are easy to implement using `.unlist = FALSE`
lm_roll <- slidify(~lm(.x ~ .y), .period = 90, .unlist = FALSE, .align = "right")
FB %>%
tidyr::drop_na() %>%
mutate(numeric_date = as.numeric(date)) %>%
mutate(rolling_lm = lm_roll(adjusted, numeric_date)) %>%
filter(!is.na(rolling_lm))
#> # A tibble: 918 × 10
#> symbol date open high low close volume adjusted numeric_date
#> <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 FB 2013-05-13 26.6 27.3 26.5 26.8 29068800 26.8 15838
#> 2 FB 2013-05-14 26.9 27.3 26.8 27.1 24930300 27.1 15839
#> 3 FB 2013-05-15 26.9 27.0 26.4 26.6 30299800 26.6 15840
#> 4 FB 2013-05-16 26.5 26.5 25.9 26.1 35499100 26.1 15841
#> 5 FB 2013-05-17 26.4 26.6 26.2 26.2 29462700 26.2 15842
#> 6 FB 2013-05-20 26.2 26.2 25.7 25.8 42402900 25.8 15845
#> 7 FB 2013-05-21 25.9 26.1 25.6 25.7 26261300 25.7 15846
#> 8 FB 2013-05-22 25.6 25.8 24.9 25.2 45314500 25.2 15847
#> 9 FB 2013-05-23 24.8 25.5 24.8 25.1 37663100 25.1 15848
#> 10 FB 2013-05-24 25.0 25.0 24.1 24.3 58727900 24.3 15849
#> # ℹ 908 more rows
#> # ℹ 1 more variable: rolling_lm <list>