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.724351 ... 0.949112] ...]
1.0         [[0.543852 ... 0.052842] ...]
2.0         [[0.185369 ... 0.955955] ...]
3.0         [[0.804769 ... 0.478975] ...]
4.0         [[0.839741 ... 0.139183] ...]
5.0         [[0.709554 ... 0.357435] ...]
6.0         [[0.971056 ... 0.832569] ...]
7.0         [[0.591195 ... 0.645518] ...]
8.0         [[0.834207 ... 0.231976] ...]
9.0         [[0.394113 ... 0.39284 ] ...]
10.0        [[0.461636 ... 0.505384] ...]
11.0        [[0.595761 ... 0.099814] ...]
12.0        [[0.441291 ... 0.892792] ...]
13.0        [[0.379898 ... 0.941123] ...]
14.0        [[3.470979e-01 ... 4.028887e-05] ...]
15.0        [[0.950539 ... 0.102514] ...]
16.0        [[0.248429 ... 0.831201] ...]
17.0        [[0.484496 ... 0.288219] ...]
18.0        [[0.305907 ... 0.873676] ...]
19.0        [[0.44384  ... 0.635743] ...]
20.0        [[0.996615 ... 0.890156] ...]
21.0        [[0.480984 ... 0.815243] ...]
22.0        [[0.009057 ... 0.296063] ...]
23.0        [[0.566717 ... 0.095101] ...]
24.0        [[0.237335 ... 0.632446] ...]
25.0        [[0.334049 ... 0.379553] ...]
26.0        [[0.649139 ... 0.55478 ] ...]
27.0        [[0.269899 ... 0.235133] ...]
28.0        [[0.18426  ... 0.000302] ...]
29.0        [[0.730784 ... 0.77545 ] ...]
...
70.0        [[0.766976 ... 0.378742] ...]
71.0        [[0.470957 ... 0.358721] ...]
72.0        [[0.296253 ... 0.463677] ...]
73.0        [[0.444259 ... 0.680758] ...]
74.0        [[0.619341 ... 0.813402] ...]
75.0        [[0.819308 ... 0.977901] ...]
76.0        [[0.338738 ... 0.073323] ...]
77.0        [[0.004642 ... 0.027166] ...]
78.0        [[0.831169 ... 0.798928] ...]
79.0        [[0.972269 ... 0.440891] ...]
80.0        [[0.252392 ... 0.766305] ...]
81.0        [[0.783114 ... 0.077648] ...]
82.0        [[0.975964 ... 0.186673] ...]
83.0        [[0.188201 ... 0.747982] ...]
84.0        [[0.691565 ... 0.610707] ...]
85.0        [[0.887413 ... 0.016115] ...]
86.0        [[0.927352 ... 0.767029] ...]
87.0        [[0.913085 ... 0.164932] ...]
88.0        [[0.372253 ... 0.887933] ...]
89.0        [[0.922098 ... 0.803032] ...]
90.0        [[0.057106 ... 0.704985] ...]
91.0        [[0.153069 ... 0.998311] ...]
92.0        [[0.598178 ... 0.352603] ...]
93.0        [[0.683037 ... 0.087507] ...]
94.0        [[0.438618 ... 0.827466] ...]
95.0        [[0.416086 ... 0.101775] ...]
96.0        [[0.977209 ... 0.381222] ...]
97.0        [[0.858024 ... 0.947596] ...]
98.0        [[0.800881 ... 0.515479] ...]
99.0        [[0.23622  ... 0.946471] ...]
dtype: float64, shape: (100, 5, 5)

tsd and ts can be converted to a pandas.Series

print(tsd.as_series())

Out:

0.0     0.907561
1.0     0.949211
2.0     0.332925
3.0     0.975265
4.0     0.933956
          ...   
95.0    0.221675
96.0    0.487117
97.0    0.170453
98.0    0.694776
99.0    0.255393
Length: 100, dtype: float64

tsdframe to a pandas.DataFrame

print(tsdframe.as_dataframe())

Out:

             a         b         c
0.0   0.372689  0.990321  0.627717
1.0   0.476747  0.391422  0.906518
2.0   0.996165  0.282564  0.188190
3.0   0.331369  0.484123  0.379352
4.0   0.557828  0.228148  0.536190
...        ...       ...       ...
95.0  0.619351  0.802106  0.115688
96.0  0.353163  0.455128  0.370743
97.0  0.481119  0.249854  0.404145
98.0  0.686291  0.147447  0.384265
99.0  0.368626  0.423458  0.271494

[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.724351 ... 0.949112] ...]
1           [[0.543852 ... 0.052842] ...]
2           [[0.185369 ... 0.955955] ...]
3           [[0.804769 ... 0.478975] ...]
4           [[0.839741 ... 0.139183] ...]
5           [[0.709554 ... 0.357435] ...]
6           [[0.971056 ... 0.832569] ...]
7           [[0.591195 ... 0.645518] ...]
8           [[0.834207 ... 0.231976] ...]
9           [[0.394113 ... 0.39284 ] ...]
dtype: float64, shape: (10, 5, 5)

First column. Return a Tsd

print(tsdframe[:,0])

Out:

Time (s)
----------  ---------
0.0         0.372689
1.0         0.476747
2.0         0.996165
3.0         0.331369
4.0         0.557828
5.0         0.237749
6.0         0.606371
7.0         0.0558349
8.0         0.317512
9.0         0.0755477
10.0        0.368763
11.0        0.617318
12.0        0.69674
13.0        0.787051
14.0        0.531482
15.0        0.112259
16.0        0.793374
17.0        0.271073
18.0        0.0289157
19.0        0.885507
20.0        0.727795
21.0        0.130178
22.0        0.721132
23.0        0.651734
24.0        0.172536
25.0        0.145156
26.0        0.658188
27.0        0.784001
28.0        0.211155
29.0        0.261133
...
70.0        0.542234
71.0        0.189216
72.0        0.677946
73.0        0.426201
74.0        0.503443
75.0        0.696238
76.0        0.140678
77.0        0.391408
78.0        0.341915
79.0        0.628866
80.0        0.370892
81.0        0.892997
82.0        0.264863
83.0        0.626343
84.0        0.404153
85.0        0.38557
86.0        0.715252
87.0        0.680071
88.0        0.67774
89.0        0.385343
90.0        0.81726
91.0        0.596216
92.0        0.527388
93.0        0.898326
94.0        0.770102
95.0        0.619351
96.0        0.353163
97.0        0.481119
98.0        0.686291
99.0        0.368626
dtype: float64, shape: (100,)

First element. Return a numpy ndarray

print(tsdtensor[0])

Out:

[[0.72435096 0.94857444 0.73781729 0.20186737 0.94911232]
 [0.48319029 0.94536147 0.3797242  0.06888461 0.34710615]
 [0.53773191 0.39277489 0.52829878 0.60118342 0.94126276]
 [0.80977075 0.14071337 0.18758527 0.37156552 0.28863518]
 [0.25520505 0.81963385 0.71328147 0.17569894 0.89712206]]

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.372689
1.0         0.476747
2.0         0.996165
3.0         0.331369
4.0         0.557828
5.0         0.237749
6.0         0.606371
7.0         0.0558349
8.0         0.317512
9.0         0.0755477
10.0        0.368763
11.0        0.617318
12.0        0.69674
13.0        0.787051
14.0        0.531482
15.0        0.112259
16.0        0.793374
17.0        0.271073
18.0        0.0289157
19.0        0.885507
20.0        0.727795
21.0        0.130178
22.0        0.721132
23.0        0.651734
24.0        0.172536
25.0        0.145156
26.0        0.658188
27.0        0.784001
28.0        0.211155
29.0        0.261133
...
70.0        0.542234
71.0        0.189216
72.0        0.677946
73.0        0.426201
74.0        0.503443
75.0        0.696238
76.0        0.140678
77.0        0.391408
78.0        0.341915
79.0        0.628866
80.0        0.370892
81.0        0.892997
82.0        0.264863
83.0        0.626343
84.0        0.404153
85.0        0.38557
86.0        0.715252
87.0        0.680071
88.0        0.67774
89.0        0.385343
90.0        0.81726
91.0        0.596216
92.0        0.527388
93.0        0.898326
94.0        0.770102
95.0        0.619351
96.0        0.353163
97.0        0.481119
98.0        0.686291
99.0        0.368626
dtype: float64, shape: (100,)
Time (s)          a        c
----------  -------  -------
0.0         0.37269  0.62772
1.0         0.47675  0.90652
2.0         0.99616  0.18819
3.0         0.33137  0.37935
4.0         0.55783  0.53619
5.0         0.23775  0.51907
6.0         0.60637  0.94231
7.0         0.05583  0.54397
8.0         0.31751  0.97247
9.0         0.07555  0.9004
10.0        0.36876  0.27342
11.0        0.61732  0.5505
12.0        0.69674  0.1011
13.0        0.78705  0.6493
14.0        0.53148  0.86106
15.0        0.11226  0.55086
16.0        0.79337  0.40683
17.0        0.27107  0.73044
18.0        0.02892  0.11192
19.0        0.88551  0.79331
20.0        0.72779  0.17356
21.0        0.13018  0.37883
22.0        0.72113  0.88574
23.0        0.65173  0.36748
24.0        0.17254  0.35611
25.0        0.14516  0.29569
26.0        0.65819  0.01034
27.0        0.784    0.95825
28.0        0.21115  0.41747
29.0        0.26113  0.14934
...
70.0        0.54223  0.0094
71.0        0.18922  0.27193
72.0        0.67795  0.27573
73.0        0.4262   0.82466
74.0        0.50344  0.89166
75.0        0.69624  0.63028
76.0        0.14068  0.96618
77.0        0.39141  0.59181
78.0        0.34191  0.70848
79.0        0.62887  0.15902
80.0        0.37089  0.11989
81.0        0.893    0.675
82.0        0.26486  0.44633
83.0        0.62634  0.40869
84.0        0.40415  0.21049
85.0        0.38557  0.347
86.0        0.71525  0.09866
87.0        0.68007  0.29784
88.0        0.67774  0.37437
89.0        0.38534  0.79259
90.0        0.81726  0.90235
91.0        0.59622  0.29871
92.0        0.52739  0.63667
93.0        0.89833  0.10263
94.0        0.7701   0.66801
95.0        0.61935  0.11569
96.0        0.35316  0.37074
97.0        0.48112  0.40415
98.0        0.68629  0.38426
99.0        0.36863  0.27149
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.53353105 0.46800492 0.5214414  0.47706481 0.50579163]
 [0.50854804 0.47551711 0.53773736 0.45878581 0.52285182]
 [0.44990416 0.5362092  0.45401792 0.50641572 0.51000034]
 [0.50704987 0.51862529 0.51133876 0.51437158 0.49926131]
 [0.52849609 0.48854246 0.50276806 0.49634894 0.51031407]]

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.56205  0.64941  0.50934  0.28384  0.68465
1.0         0.64232  0.53501  0.51741  0.4908   0.54522
2.0         0.50973  0.37118  0.45246  0.39834  0.83321
3.0         0.62595  0.52054  0.58056  0.23781  0.55746
4.0         0.58025  0.65353  0.46465  0.54976  0.5302
5.0         0.40531  0.42678  0.28605  0.28867  0.42466
6.0         0.7041   0.48811  0.30012  0.49339  0.58167
7.0         0.70272  0.44418  0.51299  0.59779  0.46479
8.0         0.50005  0.3329   0.59094  0.6578   0.47963
9.0         0.39658  0.36411  0.40694  0.4274   0.43288
10.0        0.68007  0.58142  0.49816  0.6098   0.36945
11.0        0.22493  0.38493  0.43518  0.5641   0.54234
12.0        0.28988  0.5185   0.34603  0.54112  0.55459
13.0        0.53798  0.45588  0.33611  0.67025  0.53784
14.0        0.44731  0.35091  0.37446  0.30474  0.27448
15.0        0.80838  0.70151  0.56256  0.62052  0.55756
16.0        0.3454   0.28132  0.43882  0.39544  0.64779
17.0        0.32395  0.57226  0.54708  0.3357   0.45898
18.0        0.32634  0.39649  0.5059   0.31018  0.70956
19.0        0.37409  0.6393   0.75756  0.60808  0.57842
20.0        0.67911  0.51955  0.47072  0.55702  0.51108
21.0        0.35163  0.57815  0.54047  0.60929  0.45859
22.0        0.59266  0.40149  0.42875  0.34287  0.36398
23.0        0.34748  0.53969  0.39961  0.38409  0.47461
24.0        0.49091  0.68431  0.51776  0.36438  0.35541
25.0        0.40533  0.57742  0.62257  0.44043  0.46703
26.0        0.39267  0.31961  0.50092  0.54115  0.62593
27.0        0.54856  0.49215  0.61774  0.4436   0.34741
28.0        0.48281  0.60898  0.4282   0.69653  0.46404
29.0        0.43398  0.538    0.56538  0.45487  0.60981
...
70.0        0.47547  0.51538  0.43533  0.36965  0.55387
71.0        0.37978  0.52571  0.45079  0.60621  0.46674
72.0        0.44125  0.68302  0.61332  0.61948  0.3556
73.0        0.46055  0.55302  0.46817  0.45044  0.69747
74.0        0.44475  0.73332  0.35038  0.45675  0.48971
75.0        0.47834  0.38236  0.42801  0.64603  0.81646
76.0        0.53092  0.52822  0.46119  0.56327  0.39571
77.0        0.3972   0.59521  0.56638  0.48681  0.35204
78.0        0.52331  0.35825  0.48123  0.56065  0.46542
79.0        0.6356   0.51206  0.51941  0.46141  0.52705
80.0        0.47248  0.55205  0.39149  0.45687  0.63985
81.0        0.6141   0.45093  0.35948  0.46126  0.44677
82.0        0.59758  0.49862  0.46335  0.32975  0.48597
83.0        0.20385  0.36298  0.35508  0.32815  0.55074
84.0        0.66521  0.43428  0.4976   0.66677  0.80371
85.0        0.64298  0.6008   0.31542  0.27444  0.48945
86.0        0.60981  0.55236  0.60327  0.47073  0.68134
87.0        0.71282  0.51345  0.64629  0.69852  0.35869
88.0        0.45608  0.60338  0.8076   0.46891  0.5035
89.0        0.62293  0.44673  0.4344   0.54843  0.36314
90.0        0.39411  0.30054  0.34563  0.59831  0.55951
91.0        0.43003  0.45006  0.42394  0.53088  0.70094
92.0        0.51766  0.40158  0.59956  0.72212  0.42371
93.0        0.65267  0.35473  0.43446  0.56334  0.29209
94.0        0.51981  0.45472  0.20538  0.50397  0.47142
95.0        0.53561  0.49675  0.40884  0.29142  0.35425
96.0        0.58066  0.69882  0.56941  0.54409  0.42146
97.0        0.69248  0.44083  0.60484  0.49142  0.38896
98.0        0.42643  0.60905  0.69575  0.44603  0.46401
99.0        0.30842  0.53751  0.5303   0.49977  0.56646
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.59476  -0.40932   2.57014   0.59476  -0.40932  ...
1           -0.08458  -1.39378  -2.38831  -0.08458  -1.39378  ...
2           -1.39845  -0.70441   0.95604  -1.39845  -0.70441  ...
3           -0.16957  -0.98979   0.46381  -0.16957  -0.98979  ...
4            0.9938   -0.53741  -1.67802   0.9938   -0.53741  ...
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.724351 ... 0.949112] ...]
1           [[0.543852 ... 0.052842] ...]
2           [[0.185369 ... 0.955955] ...]
3           [[0.804769 ... 0.478975] ...]
4           [[0.839741 ... 0.139183] ...]
dtype: float64, shape: (5, 5, 5), Time (s)
----------  -----------------------------
5           [[0.709554 ... 0.357435] ...]
6           [[0.971056 ... 0.832569] ...]
7           [[0.591195 ... 0.645518] ...]
8           [[0.834207 ... 0.231976] ...]
9           [[0.394113 ... 0.39284 ] ...]
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 1.648 seconds)

Download Python source code: tutorial_pynapple_numpy.py

Download Jupyter notebook: tutorial_pynapple_numpy.ipynb

Gallery generated by mkdocs-gallery