Skip to content

Note

Click here to download the full example code

Numpy tutorial

This tutorial shows how pynapple interact with numpy.

import numpy as np
import pynapple as nap
import pandas as pd

Multiple time series object are avaible depending on the shape of the data.

  • TsdTensor : for data with of more than 2 dimensions, typically movies.
  • TsdFrame : for column-based data. It can be easily converted to a pandas.DataFrame. Columns can be labelled and selected similar to pandas.
  • Tsd : One-dimensional time series. It can be converted to a pandas.Series.
  • Ts : For timestamps data only.

Initialization

tsdtensor = nap.TsdTensor(t=np.arange(100), d=np.random.rand(100, 5, 5), time_units="s")
tsdframe = nap.TsdFrame(t=np.arange(100), d=np.random.rand(100, 3), columns = ['a', 'b', 'c'])
tsd = nap.Tsd(t=np.arange(100), d=np.random.rand(100))
ts = nap.Ts(t=np.arange(100))

print(tsdtensor)

Out:

Time (s)
----------  -----------------------------
0.0         [[0.51727  ... 0.895404] ...]
1.0         [[0.663393 ... 0.475589] ...]
2.0         [[0.715128 ... 0.152147] ...]
3.0         [[0.97744  ... 0.191655] ...]
...
96.0        [[0.782558 ... 0.747341] ...]
97.0        [[0.943785 ... 0.172032] ...]
98.0        [[0.715992 ... 0.602271] ...]
99.0        [[0.135815 ... 0.552682] ...]
dtype: float64, shape: (100, 5, 5)

tsd and ts can be converted to a pandas.Series

print(tsd.as_series())

Out:

0.0     0.667768
1.0     0.961549
2.0     0.284037
3.0     0.861665
4.0     0.706899
          ...   
95.0    0.372483
96.0    0.462183
97.0    0.821270
98.0    0.796485
99.0    0.276541
Length: 100, dtype: float64

tsdframe to a pandas.DataFrame

print(tsdframe.as_dataframe())

Out:

             a         b         c
0.0   0.491233  0.821658  0.231000
1.0   0.021707  0.605881  0.247355
2.0   0.517196  0.360838  0.935419
3.0   0.840220  0.581280  0.320756
4.0   0.086720  0.292620  0.250157
...        ...       ...       ...
95.0  0.488267  0.673744  0.340825
96.0  0.859655  0.815793  0.270190
97.0  0.425349  0.459970  0.170645
98.0  0.666319  0.694995  0.359913
99.0  0.506265  0.712584  0.027225

[100 rows x 3 columns]

Attributes

The numpy array is accesible with the attributes .values, .d and functions .as_array(), to_numpy(). The time index array is a TsIndex object accessible with .index or .t. .shape and .ndim are also accessible.

print(tsdtensor.ndim)
print(tsdframe.shape)
print(len(tsd))

Out:

3
(100, 3)
100

Slicing

Slicing is very similar to numpy array. The first dimension is always time and time support is always passed on if a pynapple object is returned.

First 10 elements. Return a TsdTensor

print(tsdtensor[0:10]) 

Out:

Time (s)
----------  -----------------------------
0.0         [[0.51727  ... 0.895404] ...]
1.0         [[0.663393 ... 0.475589] ...]
2.0         [[0.715128 ... 0.152147] ...]
3.0         [[0.97744  ... 0.191655] ...]
...
6.0         [[0.359447 ... 0.96622 ] ...]
7.0         [[0.195038 ... 0.334129] ...]
8.0         [[0.081557 ... 0.87235 ] ...]
9.0         [[0.688747 ... 0.82844 ] ...]
dtype: float64, shape: (10, 5, 5)

First column. Return a Tsd

print(tsdframe[:,0])

Out:

Time (s)
----------  --------
0.0         0.491233
1.0         0.021707
2.0         0.517196
3.0         0.84022
...
96.0        0.859655
97.0        0.425349
98.0        0.666319
99.0        0.506265
dtype: float64, shape: (100,)

First element. Return a numpy ndarray

print(tsdtensor[0])

Out:

[[0.51727018 0.03390075 0.80112565 0.220407   0.89540419]
 [0.34067737 0.44790932 0.17439861 0.74983707 0.96356808]
 [0.20851396 0.24139841 0.15517256 0.12697945 0.39269327]
 [0.70361303 0.63303247 0.18126372 0.31986829 0.79197851]
 [0.46459993 0.50450667 0.56674669 0.4214567  0.61710529]]

The time support is never changing when slicing time down.

print(tsd.time_support)
print(tsd[0:20].time_support)

Out:

            start    end
       0        0     99
shape: (1, 2), time unit: sec.
            start    end
       0        0     99
shape: (1, 2), time unit: sec.

TsdFrame offers special slicing similar to pandas.DataFrame.

Only TsdFrame can have columns labelling and indexing.

print(tsdframe.loc['a'])
print(tsdframe.loc[['a', 'c']])

Out:

Time (s)
----------  --------
0.0         0.491233
1.0         0.021707
2.0         0.517196
3.0         0.84022
...
96.0        0.859655
97.0        0.425349
98.0        0.666319
99.0        0.506265
dtype: float64, shape: (100,)
Time (s)          a        c
----------  -------  -------
0.0         0.49123  0.231
1.0         0.02171  0.24736
2.0         0.5172   0.93542
3.0         0.84022  0.32076
...
96.0        0.85965  0.27019
97.0        0.42535  0.17065
98.0        0.66632  0.35991
99.0        0.50626  0.02723
dtype: float64, shape: (100, 2)

Arithmetic

Arithmetical operations works similar to numpy

tsd = nap.Tsd(t=np.arange(5), d=np.ones(5))
print(tsd + 1)

Out:

Time (s)
----------  --
0            2
1            2
2            2
3            2
4            2
dtype: float64, shape: (5,)

It is possible to do array operations on the time series provided that the dimensions matches. The output will still be a time series object.

print(tsd - np.ones(5))

Out:

Time (s)
----------  --
0            0
1            0
2            0
3            0
4            0
dtype: float64, shape: (5,)

Nevertheless operations like this are not permitted :

try:
    tsd + tsd
except Exception as error:
    print(error)

Out:

operand type(s) all returned NotImplemented from __array_ufunc__(<ufunc 'add'>, '__call__', Time (s)
----------  --
0            1
1            1
2            1
3            1
4            1
dtype: float64, shape: (5,), Time (s)
----------  --
0            1
1            1
2            1
3            1
4            1
dtype: float64, shape: (5,)): 'Tsd', 'Tsd'

Array operations

The most common numpy functions will return a time series if the output first dimension matches the shape of the time index.

Here i average along the time axis and get a numpy array.

print(np.mean(tsdtensor, 0))

Out:

[[0.52589452 0.50174754 0.50506025 0.48152077 0.51595008]
 [0.55095398 0.46214611 0.54968335 0.51852571 0.52859276]
 [0.47158591 0.47607442 0.440397   0.55331884 0.48584168]
 [0.53460863 0.48979848 0.50509807 0.50842717 0.52187273]
 [0.47743813 0.53697914 0.52845496 0.47686796 0.47048325]]

Here I average across the second dimension and get a TsdFrame

print(np.mean(tsdtensor, 1))

Out:

Time (s)          0        1        2        3        4
----------  -------  -------  -------  -------  -------
0.0         0.44693  0.37215  0.37574  0.36771  0.73215
1.0         0.33879  0.72026  0.55459  0.33577  0.56504
2.0         0.6017   0.50521  0.63258  0.6617   0.33103
3.0         0.59543  0.59335  0.59358  0.4719   0.37095
...
96.0        0.5188   0.59509  0.42638  0.49497  0.56845
97.0        0.49106  0.41528  0.43646  0.54842  0.37963
98.0        0.57957  0.46595  0.55713  0.6007   0.37686
99.0        0.3893   0.74429  0.44128  0.36305  0.48983
dtype: float64, shape: (100, 5)

This is not true for fft functions though.

try:
    np.fft.fft(tsd)
except Exception as error:
    print(error)

Out:

no implementation found for 'numpy.fft.fft' on types that implement __array_function__: [<class 'pynapple.core.time_series.Tsd'>]

Concatenating

It is possible to concatenate time series providing than they don't overlap meaning time indexe should be already sorted through all time series to concatenate

tsd1 = nap.Tsd(t=np.arange(5), d=np.ones(5))
tsd2 = nap.Tsd(t=np.arange(5)+10, d=np.ones(5)*2)
tsd3 = nap.Tsd(t=np.arange(5)+20, d=np.ones(5)*3)

print(np.concatenate((tsd1, tsd2, tsd3)))

Out:

Time (s)
----------  --
0.0          1
1.0          1
2.0          1
3.0          1
...
21.0         3
22.0         3
23.0         3
24.0         3
dtype: float64, shape: (15,)

It's also possible to concatenate vertically if time indexes matches up to pynapple float precision

tsdframe = nap.TsdFrame(t=np.arange(5), d=np.random.randn(5, 3))

print(np.concatenate((tsdframe, tsdframe), 1))

Out:

Time (s)           0         1         2         3         4  ...
----------  --------  --------  --------  --------  --------  -----
0           -1.41809  -0.58444  -0.03468  -1.41809  -0.58444  ...
1            0.42963   0.12006   0.13157   0.42963   0.12006  ...
2            1.70302   1.76859   0.41192   1.70302   1.76859  ...
3            0.57145   0.9053   -0.68933   0.57145   0.9053   ...
4            1.91562  -2.25739  -0.19457   1.91562  -2.25739  ...
dtype: float64, shape: (5, 6)

Spliting

Array split functions are also implemented

print(np.array_split(tsdtensor[0:10], 2))

Out:

[Time (s)
----------  -----------------------------
0           [[0.51727  ... 0.895404] ...]
1           [[0.663393 ... 0.475589] ...]
2           [[0.715128 ... 0.152147] ...]
3           [[0.97744  ... 0.191655] ...]
4           [[0.035912 ... 0.160205] ...]
dtype: float64, shape: (5, 5, 5), Time (s)
----------  -----------------------------
5           [[0.629097 ... 0.860984] ...]
6           [[0.359447 ... 0.96622 ] ...]
7           [[0.195038 ... 0.334129] ...]
8           [[0.081557 ... 0.87235 ] ...]
9           [[0.688747 ... 0.82844 ] ...]
dtype: float64, shape: (5, 5, 5)]

Modifying

It is possible to modify a time series element wise

print(tsd1)

tsd1[0] = np.pi

print(tsd1)

Out:

Time (s)
----------  --
0            1
1            1
2            1
3            1
4            1
dtype: float64, shape: (5,)
Time (s)
----------  -------
0           3.14159
1           1
2           1
3           1
4           1
dtype: float64, shape: (5,)

It is also possible to modify a time series with logical operations

tsd[tsd.values>0.5] = 0.0

print(tsd)

Out:

Time (s)
----------  --
0            0
1            0
2            0
3            0
4            0
dtype: float64, shape: (5,)

Sorting

It is not possible to sort along the first dimension as it would break the sorting of the time index

tsd = nap.Tsd(t=np.arange(100), d=np.random.rand(100))

try:
    np.sort(tsd)
except Exception as error:
    print(error)

Out:

no implementation found for 'numpy.sort' on types that implement __array_function__: [<class 'pynapple.core.time_series.Tsd'>]

Total running time of the script: ( 0 minutes 0.810 seconds)

Download Python source code: tutorial_pynapple_numpy.py

Download Jupyter notebook: tutorial_pynapple_numpy.ipynb

Gallery generated by mkdocs-gallery