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 effects
  • error 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

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

To make it a bit more interesting (and realistic) we will add some noise.


prophet_stepwise_data

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

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

The trend stays flat and we can even predict uncertainty!