Welcome to ticts’s documentation!

A Python library for unevenly-spaced timeseries analysis.

_images/example.png

Notebooks to play around are available here.

Why ?

Sensors become omnipresents, and often the measurements are done at irregural time intervals. I found it hard to work with using pandas, and found myself always swithing back to the evenly-spaced timeseries world, by resampling at the lowest frequency applying a fill forward. This is definitely not how it should works ! And you loose information.

About TicTs

The purpose is to provide a simple and intuitive interface to manipulate this kind of data, including:

  • operations (sum, sub, mul, div, max, min)
  • setting intervals
  • methods to pass from evenly-spaced to unevenly-spaced and vice-versa

You have to keep in mind the following rules:

  • intervals are open left, closed right
  • timestamp are always localized, defaulting to UTC
  • setting a default value to your timeseries might be important

QuickStart

Instanciation

import ticts
ticts.TimeSeries({'2019-01-01': 1, '2019-01-02': 2})
ticts.TimeSeries({'2019-01-01': 1, '2019-01-02': 2}, default=0)

import datetime
dt1 = datetime.datetime(2019, 1, 1)
ticts.TimeSeries({dt1: 1, '2019-01-02': 2})

Samples

In [1]: dt1
Out[1]: Timestamp('2019-01-01 00:00:00+0000', tz='UTC')

In [2]: onehour
Out[2]: datetime.timedelta(seconds=3600)

In [3]: smallts
Out[3]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: 1,
2019-01-01T03:00:00+00:00: 3,
2019-01-01T06:00:00+00:00: 10,

In [4]: otherts
Out[4]: 
<TimeSeries> (default=0)
2019-01-01T02:00:00+00:00: 2,
2019-01-01T03:00:00+00:00: 3,
2019-01-01T05:00:00+00:00: 5,

GetItem

An interval is closed left, open right: [ , [

In [5]: smallts.index
Out[5]: SortedKeysView(SortedDict({Timestamp('2019-01-01 01:00:00+0000', tz='UTC'): 1, Timestamp('2019-01-01 03:00:00+0000', tz='UTC'): 3, Timestamp('2019-01-01 06:00:00+0000', tz='UTC'): 10}))

# Accessing value at key
In [6]: smallts[dt1 + onehour]
Out[6]: 1

In [7]: smallts[dt1]  # no default set

In [8]: otherts[dt1]  # default set
Out[8]: 0

# Accessing values sliced
In [9]: smallts[dt1: dt1 + 5 * onehour]  # calls TimeSeries.slice
Out[9]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: 1,
2019-01-01T03:00:00+00:00: 3,

# Getting previous is the default
In [10]: key = dt1 + 2 * onehour

In [11]: smallts[key, 'previous'] == smallts[key] == 1
Out[11]: True

# linear interpolation is available
In [12]: smallts[key, 'linear']
Out[12]: 2.0

Set Item, Set Interval

Setting a default to your TimeSeries object is mandatory in order to set intervals.

In [13]: ts = TimeSeries(smallts, default=0)

In [14]: ts[dt1 + onehour] = 2

In [15]: print(ts)
<TimeSeries> (default=0)
2019-01-01T01:00:00+00:00: 2,
2019-01-01T03:00:00+00:00: 3,
2019-01-01T06:00:00+00:00: 10,

In [16]: start = dt1 + 4 * onehour

In [17]: end = dt2 + 7 * onehour

In [18]: ts.set_interval(start, end, 7)

In [19]: print(ts)
<TimeSeries> (default=0)
2019-01-01T01:00:00+00:00: 2,
2019-01-01T03:00:00+00:00: 3,
2019-01-01T04:00:00+00:00: 7,
2019-01-02T07:00:00+00:00: 10,

# same as
In [20]: ts[start: end] = 7

In [21]: print(ts)
<TimeSeries> (default=0)
2019-01-01T01:00:00+00:00: 2,
2019-01-01T03:00:00+00:00: 3,
2019-01-01T04:00:00+00:00: 7,
2019-01-02T07:00:00+00:00: 10,

Operations

Sum

In [22]: smallts + 10
Out[22]: 
<TimeSeries> (default=None)
2019-01-01T01:00:00+00:00: 11,
2019-01-01T03:00:00+00:00: 13,
2019-01-01T06:00:00+00:00: 20,

In [23]: smallts + otherts
Out[23]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: 1,
2019-01-01T02:00:00+00:00: 3,
2019-01-01T03:00:00+00:00: 6,
2019-01-01T05:00:00+00:00: 8,
2019-01-01T06:00:00+00:00: 15,

In [24]: sum([smallts, smallts, smallts])
Out[24]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: 3,
2019-01-01T03:00:00+00:00: 9,
2019-01-01T06:00:00+00:00: 30,

Sub

In [25]: smallts - otherts
Out[25]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: 1,
2019-01-01T02:00:00+00:00: -1,
2019-01-01T03:00:00+00:00: 0,
2019-01-01T05:00:00+00:00: -2,
2019-01-01T06:00:00+00:00: 5,

Comparisons

In [26]: smallts <= 10
Out[26]: 
<TimeSeries> (default=None)
2019-01-01T01:00:00+00:00: True,
2019-01-01T03:00:00+00:00: True,
2019-01-01T06:00:00+00:00: True,

In [27]: smallts <= otherts
Out[27]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: False,
2019-01-01T02:00:00+00:00: True,
2019-01-01T03:00:00+00:00: True,
2019-01-01T05:00:00+00:00: True,
2019-01-01T06:00:00+00:00: False,

In [28]: smallts < 10
Out[28]: 
<TimeSeries> (default=None)
2019-01-01T01:00:00+00:00: True,
2019-01-01T03:00:00+00:00: True,
2019-01-01T06:00:00+00:00: False,

In [29]: smallts < otherts
Out[29]: 
<TimeSeries>
2019-01-01T01:00:00+00:00: False,
2019-01-01T02:00:00+00:00: True,
2019-01-01T03:00:00+00:00: False,
2019-01-01T05:00:00+00:00: True,
2019-01-01T06:00:00+00:00: False,

In [30]: smallts >= 10
Out[30]: 
<TimeSeries> (default=None)
2019-01-01T01:00:00+00:00: False,
2019-01-01T03:00:00+00:00: False,
2019-01-01T06:00:00+00:00: True,

In [31]: smallts > 10
Out[31]: 
<TimeSeries> (default=None)
2019-01-01T01:00:00+00:00: False,
2019-01-01T03:00:00+00:00: False,
2019-01-01T06:00:00+00:00: False,

TimeSeries

class ticts.timeseries.TimeSeries(data=None, default=No default, name='value', permissive=True, tz='UTC')[source]

TimeSeries object.

Parameters:
  • default – The default value of timeseries.
  • permissive (bool) – Whether to allow accessing non-existing values or not. If is True, getting non existing item returns None. If is False, getting non existing item raises.
compact()[source]

Convert this instance to a compact version: consecutive measurement of the same value are discarded.

Returns:TimeSeries
empty

Return whether the TimeSeries is empty or not.

iterintervals(end=None)[source]

Iterator that contain start, end of intervals.

Parameters:end (datetime) – right bound of last interval.
lower_bound

Return the lower bound time index.

set_interval(start, end, value)[source]

Set a value for an interval of time.

Parameters:
  • start (datetime or str) – lower bound
  • end (datetime or str) – upper bound
  • value – the value to be set
Returns:

self

Raises:

NotImplementedError – when no default is set.

slice(start, end)[source]

Slice your timeseries for give interval.

Parameters:
  • start (datetime or str) – lower bound
  • end (datetime or str) – upper bound
Returns:

TimeSeries sliced

upper_bound

Return the upper bound time index.

CHANGES

0.4.0

  • [FIX] iterintervals on new python3.7+ (PEP 479)

0.3.5

  • Add .keys method to TimeSeries (#21)

0.3.4

  • Add update method to TimeSeries (#20)

0.3.3

  • Add iplot method (#18)
  • Some renames and ValueError instead of Exception
  • Make doc build works again
  • solve it adding _kwargs_special_keys property
  • Add check to try inferring the frequency
  • Try to infer the frequencies when to_dataframe

0.3.1

  • Be permissive on division with zero as default

0.3.0

  • Update Readme
  • Create TictsMagicMixin for builtin nethods of TimeSeries
  • add it
  • Linting
  • Rework it, no longer inherit from SortedDict
  • add test on values
  • First implementation

0.2.4

  • Small fix on div

0.2.3

  • Precise which super for equals

0.2.2

  • Render testing available at ticts package place

0.2.1

  • Re-organize code
  • Add extensions to pandas objects ‘to_ticts’
  • Fix sphinx doc building
  • Add io to_json / from_json

0.2.0

  • Linting
  • fix pytest version
  • update to_dataframe method to use self.name
  • Add operations
  • Remove arrow dep
  • Rework init and copy methods to accept pd.DataFrame or pd.Series
  • Renames and pandas as mandatory dep
  • Clean up small garbage
  • Go for a no default object with repr
  • Add __eq__ as operation per key

0.1.7

  • Add iterintervals method
  • Remove useless timestamp_converter
  • use bisect

0.1.6

  • Fix bug of set_interval on emptyts
  • Add some more tests
  • only go for python 3.6 at the moment
  • Add other python version

0.1.5

  • Add deploy as stage
  • Add ignore on /prof

0.1.4

  • Make use of SortedDict methods for performances

0.1.3

  • restructured text of PyPI does not allow image in title
  • Skip cleanup in deploy
  • Improve notebook
  • change strategy to be able to build doc
  • Update changelog

0.1.2

  • Fix on rule of slice out of right bound
  • Improving index
  • Add more quickstart
  • Fix issue on set_interval
  • Add scale
  • Work on Docs

0.1.1

  • Better handle of default value
  • Adding picture to README
  • Small fix on bounds of tutorial
  • Small fix README
  • Adapt plot ranges in Tutorial notebook
  • Add reference to traces

0.1.0

  • Enhance Readme and Add jupter notebook
  • cleaning
  • Allow operations on mixed ts with default or not
  • Add custom repr

0.0.7

  • Add permissive mode

0.0.6

  • Authorize getitem on str
  • Improving __init__
  • move the test to a more appropriate class
  • make 0 a possible value for default

0.0.5

  • Improve conditional_update and rename it

0.0.4

  • Fix bug on slice with bounds
  • Add operators le lt ge gt and conditional_update
  • Fix several bugs:
  • Add recursive operations
  • Fix bug on set_interval

0.0.2

  • Add pandas potential dep

0.0.1

  • Seed isort to get consistent behaviour in CI
  • Linter
  • Update travis cfg to deploy on tag
  • Authorize setitem on slice calling set_interval
  • re-organize tests
  • Implement _get_linear_interpolate
  • Linting
  • fix tests
  • add show diff on failure
  • Add sample method
  • cleaning up
  • Add floor and ceil operators
  • Update license in setup.cfg
  • Add test
  • fix pre-commit version
  • Fix bug on set_interval
  • Comment it
  • Change the init to get copy and deepcopy works
  • Add logging
  • Add tests for set_interval on empty
  • Add set_interval method
  • Linting
  • Comment cov when locally run
  • Linting
  • Make compact work again
  • Update precommit
  • Improve init and add slicing capabilities
  • Change of design
  • Linter
  • Go for yapf instead of black
  • Linting
  • Update pre-commit
  • Configuring travis
  • Linter
  • put first stones
  • First commit thx to cookiecutter

Indices and tables