function to add saturation trasnformations to a recipe

step_adstock(
  recipe,
  ...,
  role = NA,
  trained = FALSE,
  options = list(names = TRUE),
  skip = FALSE,
  retention = 0.5,
  groups = c("prod", "store"),
  time_id = "week",
  adstocks = NULL,
  id = rand_id("adstock")
)

Arguments

recipe

a recipes::recipe

...

variables in recipe to be effected by the step

role

defaults to NA, set to a string to change the role of the transformed variables

retention

defaults to .5, the amount of impact retained from the previous time period

id

default value will work most often, but can be set manually for use with tuning fuctions

Value

a recipe with the new adstock step appended

Examples


suppressMessages(suppressWarnings(library(tidyverse)))
suppressMessages(suppressWarnings(library(recipes)))
suppressMessages(suppressWarnings(library(tune)))
suppressMessages(suppressWarnings(library(dials)))
suppressMessages(suppressWarnings(library(mostlytidyMMM)))
#create two datasets:
mktdata<-rbind(tibble(prod='brand',store='store1',
                      sales=c(100.,100.,100.,100.,100.),
                      tv=c(10.,100.,0.,0.,100),
                      search=c(0,10,20,50.,50.),
                      week=c(1,2,3,4,5)) ,
               tibble(prod='brand',store='store2',
                      sales=c(10.,10,10,10,10),tv=c(0.,0,0,0,0),
                      search=c(0.,2,2,0,0) ,
                      week=c(1,2,3,4,5)) ) |> 
  group_by(prod,store)

mktdata2<-tibble(prod='brand',store='all',sales=100,tv=1000,search=1000,week=6) |> group_by(prod,store)

#build a recipe with two different adstock steps -- could be done in one step
rec_obj <-  recipe(sales ~ ., data = mktdata) |> step_adstock(tv,retention=.5,groups=c('prod','store')) |>
  step_adstock(search,retention=.5,groups=c('prod','store'),time_id='week') |>
  prep(training = mktdata)

#showing off the custom print function
print(rec_obj)
#> Recipe
#> 
#> Inputs:
#> 
#>       role #variables
#>    outcome          1
#>  predictor          5
#> 
#> Training data contained 10 data points and no missing data.
#> 
#> Operations:
#> 
#> Adstock Transformation with retention 0.5 ontv [trained]
#> Adstock Transformation with retention 0.5 onsearch [trained]

#see the final transformed output
bake(rec_obj,mktdata)
#> # A tibble: 10 x 6
#> # Groups:   prod, store [2]
#>    prod  store     tv search  week sales
#>    <fct> <fct>  <dbl>  <dbl> <dbl> <dbl>
#>  1 brand store1  10     0        1   100
#>  2 brand store1 105    10        2   100
#>  3 brand store1  52.5  25        3   100
#>  4 brand store1  26.2  62.5      4   100
#>  5 brand store1 113.   81.2      5   100
#>  6 brand store2   0     0        1    10
#>  7 brand store2   0     2        2    10
#>  8 brand store2   0     3        3    10
#>  9 brand store2   0     1.5      4    10
#> 10 brand store2   0     0.75     5    10

#note what happens to store = 'all' in mktdata2:
bake(rec_obj,mktdata2)
#> Warning: There were 2 warnings in `summarise()`.
#> The first warning was:
#> i In argument: `min = min(delta, na.rm = T)`.
#> i In group 1: `prod = "brand"`, `store = "all"`.
#> Caused by warning in `min()`:
#> ! no non-missing arguments to min; returning Inf
#> i Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
#> Warning: There were 2 warnings in `summarise()`.
#> The first warning was:
#> i In argument: `min = min(delta, na.rm = T)`.
#> i In group 1: `prod = "brand"`, `store = "all"`.
#> Caused by warning in `min()`:
#> ! no non-missing arguments to min; returning Inf
#> i Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
#> # A tibble: 1 x 6
#> # Groups:   prod, store [1]
#>   prod  store    tv search  week sales
#>   <fct> <fct> <dbl>  <dbl> <dbl> <dbl>
#> 1 brand NA     1000   1000     6   100

#check to make sure that per-variable application of the step_adstock and step-saturation do not break the grouping structure even though
#the output tibble from bake is ungrouped (irritatingly)

rec_both_steps<-recipe(sales~.,data=mktdata) |> 
  step_adstock(tv,retention=.1) |> step_saturation(tv,asymptote=1000,saturation_speed=.001) |>
  step_adstock(search,retention=.1,time_id='week')  |> prep()


bake(rec_both_steps,mktdata)
#> # A tibble: 10 x 6
#> # Groups:   prod, store [2]
#>    prod  store     tv search  week sales
#>    <fct> <fct>  <dbl>  <dbl> <dbl> <dbl>
#>  1 brand store1  9.95  0         1   100
#>  2 brand store1 96.1  10         2   100
#>  3 brand store1 10.0  21         3   100
#>  4 brand store1  1.01 52.1       4   100
#>  5 brand store1 95.3  55.2       5   100
#>  6 brand store2  0     0         1    10
#>  7 brand store2  0     2         2    10
#>  8 brand store2  0     2.2       3    10
#>  9 brand store2  0     0.22      4    10
#> 10 brand store2  0     0.022     5    10

#And adstock steps throw an error if time series isn't regular -- last point is two weeks 
mktdata3<-rbind(tibble(prod='brand',store='store1',
                      sales=c(100.,100.,100.,100.,100.),
                      tv=c(10.,100.,0.,0.,100),
                      search=c(0,10,20,50.,50.),
                      week=c(1,2,3,4,6)) ,
               tibble(prod='brand',store='store2',
                      sales=c(10.,10,10,10,10),tv=c(0.,0,0,0,0),
                      search=c(0.,2,2,0,0) ,
                      week=c(1,2,3,4,6)) ) |> 
  group_by(prod,store)

#not run to allow vignette to knit -- uncomment to see error

# rec1<-recipe(mktdata3) |> step_adstock(search,retention=.1,groups=c('prod','store'),
#                                         time_id='week')|>prep()

#bake(rec1,mktdata3)