The concept of time is fundamental to any kind of time series analysis and simulation. This is why we have dedicated a lot of thought to its representation in thalesians.tsa.
Before we present some of these ideas, we need to make sure that thalesians.tsa appears on the Python path and import the relevant modules:
In [1]:
import os, sys
sys.path.append(os.path.abspath('../../main/python'))
from thalesians.tsa.simulation import xtimes, times
xtimesxtimes is a generator (and, by implication, an iterator; you can learn more about generators and iterators here) designed to be a source of times to thalesians.tsa routines.
In [2]:
for t in xtimes(0, 5): print(t)
Since xtimes is a generator, the times are computed lazily:
In [3]:
xtimes(0, 5)
Out[3]:
To get hold of them all at once, you need to use something like
In [4]:
list(xtimes(0, 5))
Out[4]:
or the shortcut
In [5]:
times(0, 5)
Out[5]:
which amounts to the same thing. So far, we haven't seen anything that would justify xtimes's existence: after all, we could have achieved the same result with Python's native range:
In [6]:
list(range(0, 5))
Out[6]:
In order to understand why we may need xtimes and not range we need to delve deeper into the semantics of xtimes.
xtimes takes three arguments: start, stop, and step. stop is, in fact, optional (may be None), so xtimes enables us to set up a (theoretically) infinite number of timesteps:
In [7]:
ts = []
for t in xtimes(start=1):
ts.append(t)
if len(ts) == 5: break
ts
Out[7]:
Perhaps more importantly, start and stop don't have to be ints. They may be floats, dates, times, datetimes. Respectively, stop may be an int, float, or a timedelta, for example:
In [8]:
times(start=-3., stop=5., step=2.5)
Out[8]:
In [9]:
import datetime as dt
times(dt.date(2017, 5, 5), dt.date(2017, 5, 10))
Out[9]:
(By default, the step is 1, 1., or timedelta(days=1), depending on the types of start and stop.)
In [10]:
times(dt.time(8), dt.time(12), dt.timedelta(minutes=30))
Out[10]:
In [11]:
times(dt.datetime(2017, 5, 10), dt.datetime(2017, 5, 5), dt.timedelta(days=-1))
Out[11]:
The flexibility of xtimes/times enables one to represent time using a data type that is suitable for the particular simulation and/or modelling task.
The power of xtimes extends beyond its flexibility with times. Often one needs to deal with times that aren't regularly spaced, such as those arising from a homogeneous Poisson point process. Since the step parameter of xtimes is allowed to be a callable, this can be implemented as follows:
In [12]:
import thalesians.tsa.randomness as rnd
times(0., 10., step=lambda x: rnd.exponential(2.5))
Out[12]:
(Recall that the lengths of times between the occurrences of a Poisson process are exponentially distributed.)
The type flexibility of the function wrappers found in thalesians.tsa.randomness enable one to specify the parameter of the exponential distribution as a timedelta:
In [13]:
times(dt.datetime(2017, 5, 5, 8),
dt.datetime(2017, 5, 5, 12),
lambda x: rnd.exponential(dt.timedelta(minutes=30)))
Out[13]: