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.902249 ... 0.842444] ...]
1.0         [[0.290896 ... 0.084872] ...]
2.0         [[0.507735 ... 0.636419] ...]
3.0         [[0.418388 ... 0.440117] ...]
4.0         [[0.495372 ... 0.702289] ...]
5.0         [[0.938724 ... 0.523846] ...]
6.0         [[0.45386  ... 0.616925] ...]
7.0         [[0.464156 ... 0.200255] ...]
8.0         [[0.339479 ... 0.356272] ...]
9.0         [[6.010755e-01 ... 3.935824e-04] ...]
10.0        [[0.876183 ... 0.308134] ...]
11.0        [[0.238184 ... 0.839655] ...]
12.0        [[0.657299 ... 0.927722] ...]
13.0        [[0.722882 ... 0.216304] ...]
14.0        [[0.555252 ... 0.158002] ...]
15.0        [[0.048078 ... 0.905316] ...]
16.0        [[0.272616 ... 0.129195] ...]
17.0        [[0.323391 ... 0.578888] ...]
18.0        [[0.312827 ... 0.163232] ...]
19.0        [[0.108148 ... 0.208978] ...]
...
80.0        [[0.708413 ... 0.742841] ...]
81.0        [[0.766647 ... 0.612427] ...]
82.0        [[0.630523 ... 0.451969] ...]
83.0        [[0.571982 ... 0.441983] ...]
84.0        [[0.125532 ... 0.857858] ...]
85.0        [[0.209802 ... 0.872044] ...]
86.0        [[0.778389 ... 0.379188] ...]
87.0        [[0.713128 ... 0.51951 ] ...]
88.0        [[0.659851 ... 0.058012] ...]
89.0        [[0.536828 ... 0.499993] ...]
90.0        [[0.794475 ... 0.678799] ...]
91.0        [[0.7984   ... 0.900341] ...]
92.0        [[0.926324 ... 0.330697] ...]
93.0        [[0.043319 ... 0.778185] ...]
94.0        [[0.943788 ... 0.067219] ...]
95.0        [[0.117632 ... 0.06047 ] ...]
96.0        [[0.863612 ... 0.582385] ...]
97.0        [[0.539266 ... 0.025127] ...]
98.0        [[0.593441 ... 0.716108] ...]
99.0        [[0.266038 ... 0.636628] ...]
dtype: float64, shape: (100, 5, 5)

tsd and ts can be converted to a pandas.Series

print(tsd.as_series())

Out:

0.0     0.632613
1.0     0.739292
2.0     0.946815
3.0     0.195024
4.0     0.618244
          ...   
95.0    0.802993
96.0    0.855479
97.0    0.359640
98.0    0.398215
99.0    0.032808
Length: 100, dtype: float64

tsdframe to a pandas.DataFrame

print(tsdframe.as_dataframe())

Out:

             a         b         c
0.0   0.887296  0.953563  0.557756
1.0   0.357841  0.445353  0.133775
2.0   0.170384  0.936330  0.489914
3.0   0.247259  0.345804  0.393497
4.0   0.905045  0.252069  0.317371
...        ...       ...       ...
95.0  0.075527  0.260588  0.148203
96.0  0.405333  0.958450  0.877457
97.0  0.467493  0.382767  0.614417
98.0  0.947169  0.929753  0.269624
99.0  0.997255  0.068353  0.070295

[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.902249 ... 0.842444] ...]
1           [[0.290896 ... 0.084872] ...]
2           [[0.507735 ... 0.636419] ...]
3           [[0.418388 ... 0.440117] ...]
4           [[0.495372 ... 0.702289] ...]
5           [[0.938724 ... 0.523846] ...]
6           [[0.45386  ... 0.616925] ...]
7           [[0.464156 ... 0.200255] ...]
8           [[0.339479 ... 0.356272] ...]
9           [[6.010755e-01 ... 3.935824e-04] ...]
dtype: float64, shape: (10, 5, 5)

First column. Return a Tsd

print(tsdframe[:,0])

Out:

Time (s)
----------  ----------
0.0         0.887296
1.0         0.357841
2.0         0.170384
3.0         0.247259
4.0         0.905045
5.0         0.625152
6.0         0.00653088
7.0         0.12485
8.0         0.90555
9.0         0.0225709
10.0        0.0865834
11.0        0.287028
12.0        0.374111
13.0        0.832418
14.0        0.563814
15.0        0.553835
16.0        0.814923
17.0        0.764528
18.0        0.627986
19.0        0.620948
...
80.0        0.217461
81.0        0.888294
82.0        0.554868
83.0        0.256208
84.0        0.678658
85.0        0.707709
86.0        0.593906
87.0        0.565277
88.0        0.903143
89.0        0.0964352
90.0        0.429837
91.0        0.521494
92.0        0.92201
93.0        0.923156
94.0        0.73371
95.0        0.0755266
96.0        0.405333
97.0        0.467493
98.0        0.947169
99.0        0.997255
dtype: float64, shape: (100,)

First element. Return a numpy ndarray

print(tsdtensor[0])

Out:

[[0.9022492  0.48012438 0.90699349 0.25027303 0.84244407]
 [0.94703109 0.15575843 0.38953034 0.68373    0.54507361]
 [0.012092   0.25025245 0.02074013 0.9886991  0.18360387]
 [0.37434896 0.95356155 0.797232   0.16971231 0.17037465]
 [0.44518827 0.73646442 0.41441067 0.76648054 0.3123753 ]]

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.887296
1.0         0.357841
2.0         0.170384
3.0         0.247259
4.0         0.905045
5.0         0.625152
6.0         0.00653088
7.0         0.12485
8.0         0.90555
9.0         0.0225709
10.0        0.0865834
11.0        0.287028
12.0        0.374111
13.0        0.832418
14.0        0.563814
15.0        0.553835
16.0        0.814923
17.0        0.764528
18.0        0.627986
19.0        0.620948
...
80.0        0.217461
81.0        0.888294
82.0        0.554868
83.0        0.256208
84.0        0.678658
85.0        0.707709
86.0        0.593906
87.0        0.565277
88.0        0.903143
89.0        0.0964352
90.0        0.429837
91.0        0.521494
92.0        0.92201
93.0        0.923156
94.0        0.73371
95.0        0.0755266
96.0        0.405333
97.0        0.467493
98.0        0.947169
99.0        0.997255
dtype: float64, shape: (100,)
Time (s)          a        c
----------  -------  -------
0.0         0.8873   0.55776
1.0         0.35784  0.13377
2.0         0.17038  0.48991
3.0         0.24726  0.3935
4.0         0.90505  0.31737
5.0         0.62515  0.13478
6.0         0.00653  0.12348
7.0         0.12485  0.48474
8.0         0.90555  0.92137
9.0         0.02257  0.80238
10.0        0.08658  0.35927
11.0        0.28703  0.86293
12.0        0.37411  0.27466
13.0        0.83242  0.23778
14.0        0.56381  0.84742
15.0        0.55384  0.7293
16.0        0.81492  0.02832
17.0        0.76453  0.1708
18.0        0.62799  0.55155
19.0        0.62095  0.45444
...
80.0        0.21746  0.89624
81.0        0.88829  0.9599
82.0        0.55487  0.90129
83.0        0.25621  0.6038
84.0        0.67866  0.48609
85.0        0.70771  0.37387
86.0        0.59391  0.02607
87.0        0.56528  0.24104
88.0        0.90314  0.38953
89.0        0.09644  0.34247
90.0        0.42984  0.13194
91.0        0.52149  0.47574
92.0        0.92201  0.04588
93.0        0.92316  0.71215
94.0        0.73371  0.13383
95.0        0.07553  0.1482
96.0        0.40533  0.87746
97.0        0.46749  0.61442
98.0        0.94717  0.26962
99.0        0.99726  0.0703
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.51347568 0.49446058 0.53500726 0.50098239 0.45762959]
 [0.4925235  0.40909026 0.51660309 0.488819   0.47585208]
 [0.45549733 0.49449517 0.5299586  0.50394862 0.47437464]
 [0.50087128 0.55712597 0.42578023 0.48198078 0.50251527]
 [0.46133255 0.52506831 0.47788695 0.50401268 0.44764468]]

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.53618  0.51523  0.50578  0.57178  0.41077
1.0         0.67428  0.68421  0.43814  0.40716  0.26871
2.0         0.42547  0.70222  0.68752  0.62433  0.49328
3.0         0.34903  0.28773  0.64596  0.44503  0.58098
4.0         0.38452  0.56084  0.48591  0.70833  0.47615
5.0         0.46698  0.46368  0.18923  0.45529  0.37122
6.0         0.55222  0.43578  0.48568  0.51049  0.53627
7.0         0.51018  0.38225  0.61767  0.84368  0.48774
8.0         0.2622   0.57875  0.54226  0.72334  0.41517
9.0         0.41259  0.49572  0.40938  0.43156  0.60248
10.0        0.45979  0.57256  0.51581  0.51524  0.43237
11.0        0.37234  0.42727  0.66442  0.22848  0.40334
12.0        0.39832  0.59952  0.4637   0.65248  0.47577
13.0        0.47211  0.59125  0.34287  0.38458  0.60337
14.0        0.57222  0.62067  0.61908  0.32686  0.41902
15.0        0.45264  0.52185  0.48776  0.247    0.4922
16.0        0.3585   0.49241  0.59955  0.65535  0.30873
17.0        0.47696  0.69913  0.41812  0.43023  0.41816
18.0        0.5133   0.21893  0.79759  0.41531  0.40295
19.0        0.25049  0.44713  0.48547  0.43945  0.5437
...
80.0        0.56781  0.71803  0.64131  0.40173  0.66224
81.0        0.58958  0.60541  0.51684  0.42931  0.61596
82.0        0.57774  0.33545  0.4794   0.58956  0.41852
83.0        0.34251  0.41356  0.23959  0.50609  0.40549
84.0        0.52593  0.47606  0.45442  0.2771   0.72153
85.0        0.49965  0.63168  0.56837  0.39937  0.47652
86.0        0.47871  0.31532  0.5749   0.52533  0.47582
87.0        0.4648   0.55106  0.46686  0.74069  0.57653
88.0        0.51623  0.36036  0.40833  0.48898  0.42443
89.0        0.45647  0.37862  0.35993  0.31815  0.54552
90.0        0.77378  0.30806  0.59793  0.74476  0.68348
91.0        0.59296  0.58168  0.44723  0.27781  0.37142
92.0        0.63179  0.53362  0.55889  0.35208  0.44197
93.0        0.35268  0.45847  0.67426  0.62613  0.61238
94.0        0.58449  0.45898  0.40266  0.59554  0.50655
95.0        0.60928  0.55018  0.36251  0.69143  0.412
96.0        0.5363   0.59045  0.62768  0.58455  0.55175
97.0        0.61699  0.53256  0.42877  0.41162  0.39584
98.0        0.72358  0.23427  0.49824  0.60352  0.47829
99.0        0.37784  0.62205  0.45566  0.42889  0.46082
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            1
1            1
2            1
3            1
4            1
10           2
11           2
12           2
13           2
14           2
20           3
21           3
22           3
23           3
24           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            0.69668   0.34183  -1.42264   0.69668   0.34183  ...
1           -0.98132   0.5789   -1.8448   -0.98132   0.5789   ...
2            1.50757  -0.33702  -1.00584   1.50757  -0.33702  ...
3           -0.13234  -0.3324    1.34759  -0.13234  -0.3324   ...
4            0.32814  -1.05274   0.32834   0.32814  -1.05274  ...
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.902249 ... 0.842444] ...]
1           [[0.290896 ... 0.084872] ...]
2           [[0.507735 ... 0.636419] ...]
3           [[0.418388 ... 0.440117] ...]
4           [[0.495372 ... 0.702289] ...]
dtype: float64, shape: (5, 5, 5), Time (s)
----------  -------------------------------------
5           [[0.938724 ... 0.523846] ...]
6           [[0.45386  ... 0.616925] ...]
7           [[0.464156 ... 0.200255] ...]
8           [[0.339479 ... 0.356272] ...]
9           [[6.010755e-01 ... 3.935824e-04] ...]
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.974 seconds)

Download Python source code: tutorial_pynapple_numpy.py

Download Jupyter notebook: tutorial_pynapple_numpy.ipynb

Gallery generated by mkdocs-gallery