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
.defaultwill 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
NAvalues. Set toFALSEby default, but can be switched toTRUEto 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 = FALSEto 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
sliderunder 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):
NAor.partialvalues 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:
NAor.partialvalues are added to the end to shift the series to the Left.right:
NAor.partialvalues 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>
