I’ve substantially updated the routines and process for time-series forecasting in R using NNS since this prior comment.

> require(NNS)

> require(data.table)

# Find seasonal periods

> a = NNS.seas(lynx[1:80])

# Find optimal NNS.ARMA settings using seasonal periods (a) and training.set reflecting periods to forecast (h)

> b = NNS.ARMA.optim(lynx[1:80], training.set = 46, seasonal.factor = a$all.periods$Period)

# Run NNS.ARMA with optimal parameters (b)

> c = NNS.ARMA(lynx[1:80], h = 34, seasonal.factor = b$periods, weights = b$weights, method = b$method)

# Compute RMSE

> sqrt(mean((c-tail(lynx,34))^2))

[1] 1318.007

For more detailed examples, see the following:

https://github.com/OVVO-Financial/NNS/tree/NNS-Beta-Version/examples#4-time-series-forecasting

Any and all comments / suggestions for improvement welcomed!

]]>Are there any built-in special capabilities for handling hourly data and hourly seasonality? ]]>

NNS offers an alternative to traditional ARMA models in R. I never tested it on the lynx data until reading this post. using the “vanilla” linear method:

> require(NNS);require(datasets)

> sqrt(mean((NNS.ARMA(lynx,h=34,training.set = 80,method=’lin’)-tail(lynx,34))^2))

[1] 1397.105

I think incorporating all of these insights will yield even more robust methods, echoing Andrew’s thoughts.

More examples here: https://github.com/OVVO-Financial/NNS/blob/NNS-Beta-Version/examples/NNS%20ARMA.pdf

]]>The sin/cos approach to seasonality is what I was more familiar with.

]]>Yep, comes from MAP, which is the default option. If sampling is requested, speed is equivalent to what one would expect from a model like this fitted in Stan – for the Lynx data with a plain Prophet model that I used in the example about 1 minute per chain.

]]>>>>cases where people don’t have time or skills necessary to expend modeling effort<<<

And that's a huge audience right there.

]]>I like the flexibility in model specification, including adding holidays and carrying capacity. Sometimes, though, there are continuous predictor variables. To take Phil’s example from not long ago, say you’re modeling building energy consumption, and you have good reason to believe it’s affected by outdoor air temperature. I don’t see that in prophet; are there any plans to consider something like that?

Would tgp (the treed Gaussian processes package) be a reasonable package to compare to this? I used it a bit a couple of years ago. In at least one case, I got good and relatively fast results; in other cases, it seemed to take a long time, and I didn’t figure out if that was my model or inherent to the computation.

]]>It apparently has options for MAP (optimization) and full Bayes (sampling). Helps to have the models precompiled, too.

]]>Thanks for trying Jim! Yes you’re absolutely right that we don’t do well with random walk components and are very likely to overfit them.

]]>I think for any given problem you can probably doing a better job writing down your own model. People have correctly noted that Prophet is not so different from a GAM with a piecewise constant or piecewise logistic component. We do have some tricks for detecting changepoints that work well and help with extrapolation. But mostly we’re targeting use cases where people don’t have time or skills necessary to expend modeling effort.

]]>Hey John, it’s likely an error. I got Euler’s formula wrong. You can see how it’s implemented (correctly) in code using sin/cos here: https://github.com/facebookincubator/prophet/blob/master/python/fbprophet/forecaster.py#L189

]]>The speed comes from the fact that it is MAP?

]]>I guess for the usual definitions, you should dot product against exp(-%i*omega*x) (note the minus sign). There’s also stuff about normalization. The conventions for normalization and sign and soforth vary from field to field (numerical calculation of fourier series often ignores certain constants due to speed issues and you might be required to normalize things by the constant at the end) but the concept is still basically as above… dot product of a function with the complex exponential.

]]>When this periodic seasonality stuff came up last time it was about dummy variables, and the DataColada solution was to encourage people to use daily dummy variables… which I really didn’t like. and so I just whipped up this thing using straight up “lm”

I could imagine wanting something a little better, using lmer, but the advantages here are that the whole thing runs in milliseconds. That’s of course supposed to be an advantage to Prophet too… But typically the advantage to using Stan is typically you could do something like put in priors and specify a bunch of basis functions by hand, but that’s not what Prophet is all about right?

]]>Here’s the math, it’s more complex than just taking a real part, but not much.

Define the complex fourier coefficient as the dot-product of exp(%i*omega*x) with a function f(x) over the domain 0 to 2pi (where omega is an integer). Suppose that f really is the function A*cos(omega*x) + B*sin(omega*x), then you can get a relationship between the imaginary coefficient, and the real A,B

Here’s a link to the calculation using Maxima:

]]>The caution I’d make is that if the true time series has a random walk component, then a model like the one in prophet (which is basically y_t = f(t) + e_t) will be way too confident at long prediction intervals.

]]>Section 2.2 in their paper discusses how they create the seasonal weights. Formula 5 looks a little different from what I had seen in the past on seasonality. It looks like it would give imaginary numbers unless mod(t, 365.25)=0. Would I need to take only the real component and ignore the imaginary?

]]>Wow. This has me hooked “fit a Stan time-series model, that converges within milliseconds.”

]]>Yes, absolutely. That’s how I read your post, and certainly my analysis above was not meant to “debunk” anything. I was genuinely impressed by the package that allowed me with 2 (!) lines of code to fit a Stan time-series model, that converges within milliseconds.

]]>Felix:

Yes, the point of that example was not meant to “debunk” Prophet but rather to suggest directions for improvement. The great thing about a method that runs and gives answers is that we can try it on lots of problems and use these results to learn how to do better.

]]>R code below:

m <- prophet(data.frame(ds=1:80,y=lynx[1:80]))

future <- make_future_dataframe(m,periods=35)

forecast <- predict(m,future)

sqrt(mean((lynx[-(1:80)]-forecast[-(1:80),"yhat"])^2))

Still a pretty impressive package!

]]>