@alexhallam, curious if you ever solved this to use adstock with brms? It is the same exact issue I am struggling with…
I don’t think it’s possible without pure STAN. Creating AdStock function for panel data is a pretty complicated task (as it should loop over factors and observations).
I believe you can determine AdStock while optimizing the sales ~ adstocked media var function (with nlsLM for example - on demeaned panel data or with dummies, of course) and then transfer the adstock transformed variables into brms to optimize the parameters of the curvature (like Hill) function. Though, you have to remember, that it will provide you with Hill (S-Shaped) transformed adstocked values.
This solution has one major drawback - it assumes that adstock of each media channel is the same accros units as you define it before modeling in brms. It is a strong assumption, but as brms seems to be the most user-friendly R library for HB modelling I believe it’s the right way to go.
Maybe @paul.buerkner will correct me if I’m wrong. Best!
I have no experience with that kind of models so I don’t think I am of much help here.
@alexhallam @Antyteza @paul.buerkner
Hi - this topic is of interest to me as well as I work in both marketing mix models as well as in discrete choice models for over two decades. When creating Adstocked predictors the solution I use is outside the Stan ecosystem. I use Excel VBA to calculate the adstock variables and then read in the csv data to model with brms or RStan. From a practical standpoint this works perfectly for me (and helps me deliver my projects on time)
@Antyteza your point about the assumption about the Hill transformed adstock values and that the adstock is the same across the units is very valid. In real life this is never the case (99.99% of the time). Most of the digital channels (digital advertising, search, social among others) follow the shape of a log curve whereas the traditional media (TV and Print) follow an S-shaped curve. Radio is an exception and behaves like a hybrid of the two curves. However, the decay rates achieved by the different media channels are all over the place
you have the adstock function coded in the STAN-snipped.
// the adstock transformation with a vector of weights
real Adstock(row_vector t, row_vector weights) {
return dot_product(t, weights) / sum(weights);
}
all you have to do is transform your media data into a 3d-array with the shifted media in the third dimensions.
this funciton will do the trick for you:
threed ← function(x, max_lag = 13) {
require(xts)
x ← as.xts(x)
x ← scale(x, center = F)
arr ← array(dim=c(nrow(x),ncol(x),max_lag))
for(i in 1:max_lag) {arr[,i] ← xts::lag.xts(x,i-1)}
arr[is.na(arr)] ← 0
colnames(arr) ← names(x)
rownames(arr) ← as.character(index(x))
arr ← arr[-(1:max_lag),]
return(arr)
}