# Built-in functions

This tutorial presents built-in functions in runner package which goal is to maximize performance. Even if one can apply any R function with `runner::runner`, built-in functions are multiple times faster than R equivalent. Before you proceed further to this tutorial, make sure you know what the “running functions are”.

## Running aggregations

### Running `<mean,sum,min,max>_run`

Runner provides basic aggregation methods calculated within running windows. Below example showing some functions behavior for different arguments setup. `min_run` calculates current minimum for all elements of the vector. Let’s take a look at 8’th element of the vector which `min_run` is calculated on.
First setup uses default values, so algorithm is looking for minimum value in all elements before actual (i=8). By default missing values are removed before calculations by argument `na_rm = TRUE`, and also window is not specified. The default is equivalent of `base::cummin` with additional option to ignore `NA` values. In second example within window k=5, the lowest value is -3. In the last example minimum is not available due to existence of `NA`. Graphical example is reproduced below in the code.

    library(runner)
    x <- c(1, -5, 1, -3, NA, NA, NA, 1, -1, NA, -2, 3)

    data.frame(
      x,
      default = min_run(x, na_rm = TRUE),
      k_5     = min_run(x, k = 5, na_rm = TRUE),
      narm_f  = min_run(x, na_rm = FALSE))

    ##     x default k_5 narm_f
    ## 1   1       1   1      1
    ## 2  -5      -5  -5     -5
    ## 3   1      -5  -5     -5
    ## 4  -3      -5  -5     -5
    ## 5  NA      -5  -5     NA
    ## 6  NA      -5  -5     NA
    ## 7  NA      -5  -3     NA
    ## 8   1      -5  -3     NA
    ## 9  -1      -5  -1     NA
    ## 10 NA      -5  -1     NA
    ## 11 -2      -5  -2     NA
    ## 12  3      -5  -2     NA

In above example constant `k = 5` has been used which means that for each element, current minimum is calculated on last 5-elements. It may happen that one can have time series where elements are not equally spaced in time, which effects in `k = 5` not constant. In example below 5-days sum is calculated. To achieve this, one should put date variable to `idx` argument.
Illustration below shows two sums calculated in 5-days window span. In both cases 5-days fit in 3-elements windows. Equivalent R code below.

    x <- c(-0.5910, 0.0266, -1.5166, -1.3627, 1.1785, -0.9342, 1.3236, 0.6249)
    idx <- as.Date(c("1970-01-03", "1970-01-06", "1970-01-09", "1970-01-12",
                     "1970-01-13", "1970-01-16", "1970-01-17", "1970-01-19"))

    sum_run(x, k = 5, idx = idx)

    ## [1] -0.5910 -0.5644 -1.4900 -2.8793 -1.7008 -1.1184  1.5679  1.0143

Specifying `lag` argument shift of the window by number of elements or time periods (if `idx` is specified).

    x <- c(-0.5910, 0.0266, -1.5166, -1.3627, 1.1785, -0.9342, 1.3236, 0.6249)
    idx <- as.Date(c("1970-01-03", "1970-01-06", "1970-01-09", "1970-01-12",
                     "1970-01-13", "1970-01-16", "1970-01-17", "1970-01-19"))

    sum_run(x, k = 5, lag = 2, idx = idx)

    ## [1]      NA -0.5910 -0.5644 -1.4900 -1.5166 -0.1842 -0.1842  1.5679

### Running streak

To count consecutive elements in specified window one can use `streak_run`. Following figure illustrates how streak is calculated with three different options setup for 9th element of the input vector `x`. First shows default configuration, with full window and `na_rm = TRUE`. Second example count within `k = 4` window with count reset on `NA`. Last example counting streak with continuation after `NA`. Visualization also supported with corresponding R code.

    x <- c("A", "B", "A", "A", "B", "B", "B", NA, "B", "B", "A", "B")
    data.frame(
      x,
      s0 = streak_run(x),
      s1 = streak_run(x, k = 4, na_rm = FALSE),
      s2 = streak_run(x, k = 4))

    ##       x s0 s1 s2
    ## 1     A  1  1  1
    ## 2     B  1  1  1
    ## 3     A  1  1  1
    ## 4     A  2  2  2
    ## 5     B  1  1  1
    ## 6     B  2  2  2
    ## 7     B  3  3  3
    ## 8  <NA>  3 NA  3
    ## 9     B  4 NA  3
    ## 10    B  5 NA  3
    ## 11    A  1  1  1
    ## 12    B  1  1  1

Streak is often used in sports to count number of wins or loses of the team/player. To count consecutive wins or loses in 5-days period, one have to specify `k = 5` and include dates into `idx` argument. Specifying `lag` shifts window bounds by number of elements or time periods (if `idx` is specified).

    x <- c("W", "W", "L", "L", "L", "W", "L", "L")
    idx <- as.Date(c("2019-01-03", "2019-01-06", "2019-01-09", "2019-01-12",
                     "2019-01-13", "2019-01-16", "2019-01-17", "2019-01-19"))

    data.frame(
      idx,
      x,
      streak_5d     = streak_run(x, k = 5, idx = idx),
      streak_5d_lag = streak_run(x, k = 5, lag = 1, idx = idx))

    ##          idx x streak_5d streak_5d_lag
    ## 1 2019-01-03 W         1            NA
    ## 2 2019-01-06 W         2             1
    ## 3 2019-01-09 L         1             1
    ## 4 2019-01-12 L         2             1
    ## 5 2019-01-13 L         3             2
    ## 6 2019-01-16 W         1             2
    ## 7 2019-01-17 L         1             1
    ## 8 2019-01-19 L         2             1

## Utility functions

### Improved lag

Idea of `lag_run` is the same as well known `stats::lag`, with distinction that `lag_run` can depend on time or any other indexes passed to `idx` argument. This means that `lag_run` can shift by `lag` elements of the vector or by `lag` time periods (if `idx` is specified).

    x <- c(-0.5910, 0.0266, -1.5166, -1.3627, 1.1785, -0.9342, 1.3236, 0.6249)
    idx <- as.Date(c("1970-01-03", "1970-01-06", "1970-01-09", "1970-01-12",
                     "1970-01-13", "1970-01-16", "1970-01-17", "1970-01-19"))

    lag_run(x, lag = 3, idx = idx)

    ## [1]      NA -0.5910  0.0266 -1.5166      NA  1.1785      NA -0.9342

### Filling missing values

Function used to replace `NA` with previous non-NA element. To understand how `fill_run` works, take a look on illustration. Row ‘x’ represents input, and another rows represent output with `NA` replaced by `fill_run` with different options setup (`run_for_first = TRUE` and `only_within = TRUE` respectively). By default, `fill_run` replaces all `NA` if they were preceded by any value. If `NA` appeared in the beginning of the vector then it would not be replaced. But if user specify `run_for_first = TRUE` initial empty values values will be replaced by next non-empty value. Option `only_within = TRUE` means that `NA` values would be replaced if they were surrounded by pair of identical values. No windows provided in this functionality.

    x <- c(NA, NA, "b", "b", "a", NA, NA, "a", "b", NA, "a", "b")
    data.frame(x,
               f1 = fill_run(x),
               f2 = fill_run(x,run_for_first = TRUE),
               f3 = fill_run(x, only_within = TRUE))

    ##       x   f1 f2   f3
    ## 1  <NA> <NA>  b <NA>
    ## 2  <NA> <NA>  b <NA>
    ## 3     b    b  b    b
    ## 4     b    b  b    b
    ## 5     a    a  a    a
    ## 6  <NA>    a  a    a
    ## 7  <NA>    a  a    a
    ## 8     a    a  a    a
    ## 9     b    b  b    b
    ## 10 <NA>    b  b <NA>
    ## 11    a    a  a    a
    ## 12    b    b  b    b

### Running which

To obtain index number of element matching some condition in window, one can use `which_run`, which returns index of `TRUE` element appeared before n-th element of a vector. If `na_rm = TRUE` is specified, missing is treated as `FALSE`, and is ignored while searching for `TRUE`. While user set `na_rm = FALSE` like in second example, function returns `NA`, because in following window `TRUE` appears after missing and it’s impossible to be certain which is first (missing is an element of unknown value - could be `TRUE` or `FALSE`).

    x <- c(T, T, T, F, NA, T, F, NA, T, F, T, F)
    data.frame(
      x,
      s0 = which_run(x, which = "first"),
      s1 = which_run(x, na_rm = FALSE, k = 5, which = "first"),
      s2 = which_run(x, k = 5, which = "last"))

    ##        x s0 s1 s2
    ## 1   TRUE  1  1  1
    ## 2   TRUE  1  1  2
    ## 3   TRUE  1  1  3
    ## 4  FALSE  1  1  3
    ## 5     NA  1  1  3
    ## 6   TRUE  1  2  6
    ## 7  FALSE  1  3  6
    ## 8     NA  1 NA  6
    ## 9   TRUE  1 NA  9
    ## 10 FALSE  1  6  9
    ## 11  TRUE  1 NA 11
    ## 12 FALSE  1 NA 11

`which` argument (‘first’ or ‘last’) used with `which_run` determines which index of matching element should be returned from window. In below illustration in `k = 4` elements window there are two `TRUE` values, and depending on `which` argument output is equal `2` or `4`.