Adding custom trends to Facebook Prophet
What is Facebook Prophet?
Facebook Prophet is a great algorithm for forecasting “human” data with high seasonality. Under the hood it uses an additive algorithm
y(t) = g(t) + s(t) + h(t) + error
with
y(t)
the target value as a function of time,g(t)
a trend function (e.g. piecewise linear or logistic growth),s(t)
the seasonality components (e.g. daily or yearly recurring fluctuations)h(t)
holiday effectserror
I shouldn’t explain this
On top of this you can easily add extra regressors based on numeric features. Due to its simple architecture, its conclusions are very explainable. Not unimportant in a hard to validate field such as forecasting.
![fbprophet_components](/images/fb_prophet_components.png)
A glance at the plot above, you can get an idea of the reasons behind a trained models predictions.
Datasets with disruptions
Suppose we have a forecasting problem that has sudden disruptions in there (think legislative changes, pricing plan changes, global pandemics, … ). We will assume that the seasonalities stay the same before and after the disruption.
Our dataset might look a bit like the one in the picture below. As we see it has a very strong weekly seasonality following a sine pattern.
![prophet_stepwise_data](/images/prophet_stepwise_data.png)
To make it a bit more interesting (and realistic) we will add some noise.
![prophet_stepwise_data](/images/prophet_stepwise_data_and_noise.png)
So what will happen if we let Prophet on the described problem? You can clearly see that the data is ‘jumping’ between plateaus. But the model thinks it is an upward trend. Suppose that the real event was a legislative change, then the model thinks similar changes will occur in the future.
![prophet_pred_normal](/images/prophet_prediction_normal.png)
The model obviously fails in this case, as it is extrapolating trends where it shouldn’t. The easiest way of handling these disruptions would be to just throw away all data before the disruption and to keep only the data after the event. (It would be the safest option; it may be that not only the mean but also the seasonalities have changed!) Obviously this robs us from our most precious resource data and the possibility to detect long period seasonalities, so we should probably not do this.
The step function trend
Let’s find another solution to our problem. The trend function in Prophet is just one of the components of the model. So in theory you should be able to put any trend function in there.
If we jump into the stan file of Prophet, we see something like this
vector linear_trend(
real k,
real m,
vector delta,
vector t,
matrix A,
vector t_change
) {
return (k + A * delta) .* t + (m + A * (-t_change .* delta));
}
Here t
are the different timestamps we want to predict on. The float k
is the basetrend, delta
are modifications (at the changepoints
) to that trend and A
is a len(t)
by len(delta)
matrix that make sure that delta
is applied at the right timestamps. The rest are the ‘base’ bias m
and some modifiers to make the function continuous.
So let’s try and hack this.
If delta
can be used to make modifications to k
, we can also do the same to m
. Let’s add another trend function
vector step_trend(
real m,
vector delta,
matrix A
) {
return (m + A * delta)
}
We are only keeping m
and making modifications to it at the changepoints with A
and delta
.
Also we’ll register our new trend in transformed parameters
.
} else if (trend_indicator == 3) {
trend = step_trend(m, delta, A);
}
Some other fairly straightforward modifications need to be made in the Python code. I will leave this as an exercise to the reader. :) Also make sure to recompile your stan file.
Let’s try out our new and improved forecasting model.
![prophet_pred_step](/images/prophet_prediction_step.png)
The trend stays flat and we can even predict uncertainty!