13 min read

Forecasting New MRR in Publish with Prophet

In this analysis we’ll forecast new MRR for the most important plans of the Publish product. We’ll break down the trends in MRR growth into daily, weekly, and yearly seasonality. The table at the end of this analysis includes the daily forecasts for new MRR growth. These are the daily targets that we’re hoping to beat.

Because ChartMogul’s API doesn’t let us filter by plan group, we’ll only forecast new MRR for the most important Publish plans: Pro, Premium, Small Business, Medium Business, Large Business. We’ll collect all of the daily MRR movements since January 1, 2018.

# get mrr movements from chartmogul api
mrr <- get_mrr_metrics(metric = "mrr",
                       start_date = "2018-01-01",
                       end_date = "2019-07-24",
                       interval = "day",
                       plans = plan_names)
## [1] "Getting data from: https://api.chartmogul.com/v1/metrics/mrr"
# tidy the data
mrr <- mrr %>% 
  mutate(new_mrr = `mrr-new-business` + `mrr-reactivation`,
         new_mrr = new_mrr / 100,
         date = as.Date(date))

Let’s look at new + reactivation MRR for Publish over time.

We can see that new + reactivation MRR grows by roughly $2.5k each day, and that it increased by quite a bit in the middle of 2018. What happened then?

Forecasting New MRR

We first need to create a dataframe with columns ds and y, containing the date and numeric value respectively. The ds column should be YYYY-MM-DD for a date, or YYYY-MM-DD HH:MM:SS for a timestamp.

# filter  mrr to give us data we want
new_mrr <- mrr %>% 
  dplyr::select(date, new_mrr)

# create dataframe to send to prophet
prophet_df <- new_mrr %>% 
  rename(ds = date, y = new_mrr)

# fit model
mod <- prophet(prophet_df, weekly.seasonality = TRUE, yearly.seasonality = TRUE)

Predictions are made on a dataframe with a column ds containing the dates for which predictions are to be made. The make_future_dataframe function takes the model object and a number of periods to forecast and produces a suitable dataframe. By default it will also include the historical dates so we can evaluate in-sample fit.

# make future dataframe
future <- make_future_dataframe(mod, periods = 60)

Now let’s make the forecast and plot the results.

# make predictions
fcast <- predict(mod, future)

# plot results
plot(mod, fcast) +
  scale_y_continuous(labels = dollar) +
  buffer_theme() +
  labs(x = NULL, 
       y = NULL,
       title = "Forecasted New New MRR Growth",
       subtitle = "New + Reactivation MRR")

The solid blue line represents the forecast’s predicted value. The biggest source of uncertainty in the forecast is the potential for future trend changes, so the furthest months forecasted for have the highest risk of being off.

We can also plot the seasonal decomposition of the forecast.

## NULL

This graph is informative. The first panel indicates an overall negative trend in new MRR growth. Interestingly, this trend started decreasing in mid 2018.

The second panel shows weekly seasonality. New MRR growth tends to be highest on Monday and Tuesday, and falls off for the rest of the week.

The last panel shows the yearly seasonal component. We have to keep in mind that we only have data from January 2018, so less than two years of data were used to come up with an estimate of yearly seasonality. It shows that new MRR tends to increase in January, April and May, before dipping in July. It then gradually picks up in the fall before falling at the end of the year.

Forecasted Values

Let’s get the forecasted values and the confidence intervals for new MRR. The upper_bound and lower_bound represent the uncertainty interval, which is based on the variance between historic dates You can see that most of the black dots in the plot above fall within this uncertainty interval.

day forecast lower_bound upper_bound
2019-07-24 $2,473.46 $1,846.46 $3,119.62
2019-07-25 $2,416.06 $1,782.89 $3,077.41
2019-07-26 $2,014.51 $1,374.04 $2,659.48
2019-07-27 $649.11 $9.63 $1,266.80
2019-07-28 $800.52 $119.82 $1,453.98
2019-07-29 $2,664.69 $2,030.45 $3,374.41
2019-07-30 $2,634.25 $1,932.21 $3,348.10
2019-07-31 $2,458.36 $1,766.32 $3,151.91
2019-08-01 $2,397.32 $1,723.24 $3,076.82
2019-08-02 $1,993.51 $1,314.72 $2,649.81
2019-08-03 $627.29 $-53.01 $1,271.88
2019-08-04 $779.37 $84.20 $1,424.27
2019-08-05 $2,645.65 $1,980.41 $3,312.07
2019-08-06 $2,618.72 $1,958.06 $3,292.95
2019-08-07 $2,447.63 $1,780.42 $3,097.10
2019-08-08 $2,392.54 $1,670.66 $3,037.42
2019-08-09 $1,995.66 $1,400.34 $2,678.64
2019-08-10 $637.16 $1.32 $1,299.28
2019-08-11 $797.49 $133.87 $1,476.84
2019-08-12 $2,672.31 $2,035.44 $3,360.38
2019-08-13 $2,653.96 $2,035.84 $3,309.90

These are the forecasted values for New + Reactivation that we’re trying to beat. We can monitor our progress with the chart below.

The solid blue line represents the forecasted New MRR amounts, and the blue ribbon represents the prediction interval. The red dots and lines represent the actual New MRR amounts that we observe.

When you hover over a given date new_mrr will correspond to the actual observed value, yhat will correspond to the forecasted value, yhat_lower will correspond to the lower bound of the prediction interval, and yhat_upper will correspond to the upper bound of the prediction interval.