Evaluation and standardization of popular time series packages
Project description
timemachines
Autonomous, univariate, kstep ahead timeseries forecasting functions assigned Elo ratings
This package is a mere collection of sequencetosequence forecasting functions. You can:
 Use some of the functionality of a subset of the popular python timeseries packages with one line of code.
 Peruse Elo ratings or use them programatically. Find faster, lighter, lesserknown methods like thinking_fast_and_slow that might be useful for your purpose. Perhaps even adopt the use of forever functions that get better over time without your doing anything.
 Quickly determine if autonomous algorithms can reliably predict your own model's residuals.
 Make your own autonomous algorithms and watch them compete. Use various combinations (composition, stacking et cetera). Use hyperparameter tuning to turn "almost" autonomous algorithms, or combinations of the same, into fully autonomous algorithms.
There's also a recommendation colab notebook you can open and run. This project might help your package search, depending on your purposes. But it does not replace the packages themselves.
Contribute
See CONTRIBUTE.md. Also FAQ.
The package is setup for pytest and we rely pretty heavily on Github actions. You may wish to use act to run the Github actions locally.
Slack / Google Meets
See the Slack invite on my user page here.
Installation
See methodical install instructions and be patient for best results :)
I ain't gonna lie. Using multiple python timeseries packages can involve some oneoff install pain. Please use a virtual env or a new conda environement. This is reasonable advice in general but particularly so here, given all the dependencies of various timeseries packages out there. Failure to use a virtual environment could leave you in a real mess.
Quick start
This package is just a collection of "skaters" whose skating.py utilities serve as demonstrations of the usage pattern. Put simply, you just feed them one data point at a time:
from timemachines.skaters.simple.thinking import thinking_slow_and_fast
import numpy as np
y = np.cumsum(np.random.randn(1000))
s = {}
x = list()
for yi in y:
xi, x_std, s = thinking_slow_and_fast(y=yi, s=s, k=3)
x.append(xi)
This will accumulate 3step ahead prediction vectors. Or to plot actual data:
from timemachines.skaters.simple.thinking import thinking_slow_and_slow
from timemachines.skatertools.visualization.priorplot import prior_plot
from timemachines.skatertools.data.real import hospital
import matplotlib.pyplot as plt
y = hospital(n=200)
prior_plot(f=thinking_slow_and_slow,y=y)
plt.show()
There's more in examples/basic_usage.
Why do it this way?

Simple kstep ahead forecasts in functional style There are no "models" here requiring setup or estimation, only stateless functions:
x, x_hat, s = f(y,s,k)
These functions are called skaters and they take on the responsibility of incremental estimation, so you don't have to. Some are computationally efficient in this respect, whereas others are drawn from traditional packages intended for batch/offline work, and are not. It is sometimes useful to compare accuracy of fast and slow algorithms, even if the latter might not suit your production volumetrics. To that end...
1a. Simple canonical autonomous use of some functionality from packages like river, pydlm, tbats, pmdarima, statsmodels.tsa, neuralprophet, Facebook Prophet, Uber's orbit, Facebook's greykite and more.
1b. Simple fast accurate alternatives to popular time series packages. See the article comparing some fast skaters to Facebook prophet and Neural Prophet.

Ongoing, incremental, empirical evaluation. Again, see the leaderboards produced by the accompanying repository timeserieseloratings. Assessment is always out of sample and uses live, constantly updating realworld data from microprediction.org.

Terse stacking, ensembling, boosting and other combining of models. The function form makes it easy to do this, usually with one or two lines of code (again, see thinking.py for an illustration, or prophetskaterscomposed.py).

Simplified deployment. There is no state, other that that explicitly returned to the caller. For skaters relying only on the timemachines and river packages (the fast ones), the state is a pure Python dictionary trivially converted to JSON and back (for instance in a web application). See the FAQ for a little more discussion.
This package is also characterized by what isn't here.
NO CLASSES. NO DATAFRAMES. NO CEREMONY.
...just a bunch of functions sharing the same signature.
The Skater signature
To emphasize, in this package a time series "model" is a plain old function taking scalars and lists as arguments. The name timemachines is chosen because the skater functions suggest state machines for sequential assimilation of observations (as a data point arrives, forecasts for 1,2,...,k steps ahead, with corresponding standard deviations are emitted). However unlike state machines that save state themselves, here the caller is expected to maintain state from one invocation (data point) to the next. See the FAQ if this seems odd.
So, here's a tiny bit more detail about the signature adopted by all skaters in this package.
x, w, s = f( y:Union[float,[float]], # Contemporaneously observerd data,
# ... including exogenous variables in y[1:], if any.
s=None, # Prior state
k:float=1, # Number of steps ahead to forecast. Typically integer.
a:[float]=None, # Variable(s) known in advance, or conditioning
t:float=None, # Time of observation (epoch seconds)
e:float=None, # Nonbinding maximal computation time ("e for expiry"), in seconds
r:float=None) # Hyperparameters ("r" stands for for hype(r)pa(r)amete(r)s)
As noted, the function is intended to be applied repeatedly. For example one could harvest a sequence of the model predictions as follows:
def posteriors(f,y):
s = {}
x = list()
for yi in y:
xi, xi_std, s = f(yi,s)
x.append(xi)
return x
Notice the use of s={} on first invocation. Also as noted above, there are prominently positioned skating.py utilities for processing full histories  though there isn't much beyond what you see above.
Skater "y" argument
A skater function f takes a vector y, where:
 The quantity to be predicted (target) is y[0] and,
 There may be other, simultaneously observed variables y[1:] deemed helpful in predicting y[0].
See also "a" argument below.
Skater "s" argument
The state. The convention is that the caller passes the skater an empty dict on the first invocation, or to reset it. Thus the callee must initialize state if it receives an empty dictionary. It should return to the caller anything it will need for the next invocation. Skaters are pure in that sense.
Skater "k" argument
Determines the length of the term structure of predictions (and also their standard deviations) that will be returned. This cannot be varied from one invocation to the next.
Skater "a" argument
A vector of knowninadvance variables. You can also use the "a" argument for conditional prediction. This is a nice advantage of keeping skaters pure  though the caller might need to make a copy of the prior state if she intends to reuse it.
Skater "t" argument
Epoch time of the observation.
Skater "e" argument ("expiry")
Suggests a number of seconds allowed for computation, though skater's don't necessarily comply. See remarks below.
Skater "r" argument (stands for "hype(r) pa(r)amete(r)s for preskaters only)
A real skater doesn't have any hyperparameters. It's the job of the designer to make it fully autonomous. The small concession made here is the notion of a preskater: one with a single float hyperparameter in the closed interval [0,1]. Preskaters squish all tunable parameters into this interval. That's a bit tricky, so some rudimentary conventions and spacefilling functions are provided. See tuning and longer discussion below.
Return values
All skater functions return two vectors and the posterior state dictionary.
1. The first set of *k* numbers can be *interpreted* as a point estimate (but need not be)
2. The second is *typically* suggestive of a symmetric error std, or width. However a broader interpretation is possible wherein a skater *suggests* a useful affine transformation of the incoming data and nothing more.
3. The third returned value is state, and the skater expects to receive it again on the next call.
> x [float], # A vector of point estimates, or anchor points, or theos
x_std [float] # A vector of "scale" quantities (such as a standard deviation of expected forecast errors)
s Any, # Posterior state, intended for safe keeping by the callee until the next invocation
For many skaters the x_std is, as is suggested, indicative of one standard deivation.
x, x_std, x = f( .... ) # skater
x_up = [ xi+xstdi for xi,xstdi in zip(x,xstd) ]
x_dn = [ xixstdi for xi,xstdi in zip(x,xstd) ]
then very roughly the k'th next value should, with 5 out of 6 times, below the k'th entry in x_up There isn't any capability to indicate three numbers (e.g. for asymmetric conf intervals around the mean).
In returning state, the intent is that the caller might carry the state from one invocation to the next verbatim. This is arguably more convenient than having the predicting object maintain state, because the caller can "freeze" the state as they see fit, as when making conditional predictions. This also eyes lambdabased deployments and encourages tidy use of internal state  not that we succeed when calling down to statsmodels (though prophet, and others including the home grown models use simple dictionaries, making serialization trivial).
Summary of conventions:

State
 The caller, not the callee, persists state from one invocation to the next
 The caller passes s={} the first time, and the callee initializes state
 State can be mutable for efficiency (e.g. it might be a long buffer) or not.
 State should, ideally, be JSONfriendly.

Observations: target, and contemporaneous exogenous
 If y is a vector, the target is the first element y[0]
 The elements y[1:] are contemporaneous exogenous variables, not known in advance.
 Missing data can be supplied to some skaters, as np.nan.
 Most skaters will accept scalar y and a if there is only one of either.

Variables known ksteps in advance, or conditioning variables:
 Pass the vector argument a that will occur in ksteps time (not the contemporaneous one)
 Remark: In the case of k=1 there are different interpretations that are possible beyond "business day", such as "size of a trade" or "joystick up" etc.

HyperParameter space (for preskaters only)
 A float r in (0,1).
 This package provides functions to_space and from_space, for expanding to R^n using space filling curves, so that the callee's (hyper) parameter optimization can still exploit geometry, if it wants to.
See FAQ or file an issue if anything offends you greatly.
Aside: more on the e argument ...
The use of e is a fairly weak convention. In theory:
 A large expiry e can be used as a hint to the callee that there is time enough to do a 'fit', which we might define as anything taking longer than the usual function invocation.
 A negative e suggests that there isn't even time for a "proper" prediction to be made, never mind a model fit. It suggests that we are still in a burnin period where the caller doesn't care too much, if at all, about the quality of prediction. The callee (i.e. the skater) should, however, process this observation somehow because this is the only way it can receive history. There won't be another chance. Thus some skaters will use e<0 as a hint to dump the obervation into a buffer so it can be used in the next model fit. They return a naive forecast, confident that this won't matter.
Some skaters are so fast that a separate notion of 'fit' versus 'update' is irrelevant. Other skaters will periodically fit whether or not e>0 is passed.
The "e" conventions are useful for testing and assessment. You'll notice that the Elo rating code passes a sequence of e's something looking like:
1, 1, 1, ... 1 1000 1000 1000 1000 1000 ...
because it wants to allow the skaters to receive some history before they are evaluated. On the other hand, waiting for Facebook prophet to fit itself 500 times is a bit like waiting for the second coming of Christ.
Examples
 See examples
Tuning "preskaters" and more on the "r" argument for preskaters
 See tuning
Cite
Thanks
@electronic{cottontimemachines,
title = {{Timemachines: A Python Package for Creating and Assessing Autonomous TimeSeries Prediction Algorithms}},
year = {2021},
author = {Peter Cotton},
url = {https://github.com/microprediction/timemachines}
}
Project details
Release history Release notifications  RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for timemachines0.15.0py3noneany.whl
Algorithm  Hash digest  

SHA256  788974c2d11ddbc8c02bf47959f80db28624054868f251b3bdea9b41d362d10b 

MD5  1fa0b14d9fd440ca60a3e1260607f974 

BLAKE2b256  be993d50c2f160fe3baa44f4c393797859fdf10074fcbd6187e69069f17f4cfb 