mitchelloharawild / fable.prophet

fable extension for the prophet forecasting procedure
https://pkg.mitchelloharawild.com/fable.prophet
55 stars 8 forks source link

Allow arguments to be passed to the prophet() function from the {prophet} package. #15

Closed jaredlander closed 4 years ago

jaredlander commented 4 years ago

Not a bug, but a feature request.

A great feature of {prophet} is the ability to set suggested changepoints. It would be great if this, and other, arguments can be passed to the underlying function.

Specific to this particular argument, after plotting the fitted values with autoplot(), I'd like to be able to use the add_changepoints_to_plot() function to show vertical lines for the changepoints. However, this function requires a model, and I'm not quite sure how to pass multiple rows from a mable to this.

Further, the ability to make the components plot with prophet_plot_components() or with fabletools::components() %>% autoplot().

There are more use cases similar to these but you probably get where I'm going.

mitchelloharawild commented 4 years ago

A great feature of {prophet} is the ability to set suggested changepoints. It would be great if this, and other, arguments can be passed to the underlying function.

From my understanding, prophet allows you to specify changepoints using the changepoints argument. In fable.prophet, this argument exists within the growth() special. This allows specific changepoints to be specified using growth(changepoints = ...).

Specific to this particular argument, after plotting the fitted values with autoplot(), I'd like to be able to use the add_changepoints_to_plot() function to show vertical lines for the changepoints. However, this function requires a model, and I'm not quite sure how to pass multiple rows from a mable to this.

For plotting the changepoints, I think the first step would be to identify a suitable function which returns the changepoints. I suspect this belongs in either the glance() or tidy() outputs.

Further, the ability to make the components plot with prophet_plot_components() or with fabletools::components() %>% autoplot().

You should be able to plot the components using the second method you've highlighted. Is this not working as expected?

jaredlander commented 4 years ago

I did not see the growth() special, that seems pretty cool, I'll try it. Thanks for the heads up.

Change points are identified with

signif_changepoints <- m$changepoints[abs(m$params$delta) >= threshold]

where m is the model and threshold is an argument to the function. This can be seen in the add_changepoints_to_plot() function. So that could be abstracted out.

I was not able to extract the components with that second method, but I can try again.

My real intermediate goal is to be able to autoplot() the fitted values and confidence band along the changepoints for models fit on multiple datasets.

jaredlander commented 4 years ago

Ok, used growth() which allowed me to change this

prophet_mods <- the_data %>% 
  group_nest(Measurement) %>% 
  mutate(
    Model=purrr::map(data, prophet::prophet, changepoints=age$Date),
    Forecasts=purrr::map(Model, predict),
    Changepoints=purrr::map(Model, ~ .x$changepoints[abs(.x$params$delta) >= 0.01])
  )

to

prophet_fable <- the_data %>% 
  model(
    prophet=prophet(y ~ growth(changepoints=age$Date))
  ) %>% 
  mutate(
    Forecasts=purrr::map(prophet, ~ predict(.x$fit$model)),
    Changepoints=purrr::map(prophet, ~ .x$fit$model$changepoints[abs(.x$fit$model$params$delta) >= 0.01])
  )

Notice I am calling predict() to get the fitted values along with the point-wise confidence intervals. This could be due to my ignorance for getting this properly using {fable}-based tools.

I also hackily get the changepoints.

Using this code I can get everything except the confidence intervals.

prophet_aug <- prophet_fable %>% augment()
prophet_aug %>% 
  autoplot(.fitted, size=2) + 
  geom_point(aes(y=y), color='black', size=1, shape=1) + 
  geom_vline(aes(xintercept=as.Date(Changepoints)), data=change_points, color='red', linetype=2) + 
  facet_wrap(~ Measurement, scales='free_y')

image

So I instead resort to using the results of the predict() function as mentioned above.

ggplot(prophet_fitted, aes(x=ds, y=y)) + 
  geom_ribbon(aes(ymin=yhat_lower, ymax=yhat_upper), alpha=0.2, fill="#0072B2") + 
  geom_point() +
  geom_line(aes(y=yhat), color="#0072B2") +
  geom_line(aes(ds, trend), color='red') +
  geom_vline(aes(xintercept=Changepoints), data=change_points, color='red', linetype='dashed') +
  facet_wrap(~ Measurement, scales='free_y')

image

If augment() returned confidence intervals for the fitted values, then I might be able to get this all-in-one. Of course, this might already be possible and I just don't know it yet.

mitchelloharawild commented 4 years ago

Looks good. I certainly want to add confidence intervals (or better yet, distributions) to the augment() output. Reporting standard errors from a prophet model is a bit imprecise, because prophet computes intervals based on sampling techniques. I can add the changepoints somewhere in the model output for the first release, but the intervals will come at a later date.

mitchelloharawild commented 4 years ago

I've added the changepoints (with their delta values, the adjustment to the trend) to the glance() output. This should make it easy to glance a mable and then unnest the changepoints should you want to add them to a plot.

Looking into the prophet model code, the delta threshold is just in place to remove changepoints which practically do nothing. The changepoints are still there, they are just not shown. You can use filter on the changepoints to remove the ones you don't want included in the plot.

jaredlander commented 4 years ago

I will give glance() a shot and report back.