Vecteur de valeurs¶

In [36]:
#numpy
import numpy as np
np.__version__
Out[36]:
'1.26.4'
In [37]:
#nombre de valeurs
n = 1000000
In [38]:
#générer les valeurs
rng = np.random.default_rng(2024)
vec = rng.random(size=n)
#nb. de valeurs obtenues
vec.shape
Out[38]:
(1000000,)
In [39]:
#min et max
print(np.min(vec))
print(np.max(vec))
1.675090474106966e-06
0.9999998884825583

Solution 1 - Boucle¶

In [40]:
#fonction pour transformer une valeur
def trans(x):
    if (x < 0.1):
        res = 1
    elif (x < 0.3):
        res = x**2
    elif (x < 0.8):
        res = (x+1)*31.5
    else:
        res = 1245
    return res
In [42]:
#test de la fonction
trans(0.25)
Out[42]:
0.0625
In [43]:
#et on boucle sur le vecteur
def boucle_v1(v):
    result = []
    for x in v:
        result.append(trans(x))
    return np.array(result)
In [44]:
#lancement
z1 = boucle_v1(vec)
print(np.sum(z1))
272817349.82839215
In [45]:
#temps de traitement
%timeit -r 10 -n 1 boucle_v1(vec)
372 ms ± 10.2 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
In [46]:
#boucle liste bis
def boucle_v1_bis(v):
    result = [trans(x) for x in v]
    return np.array(result)
In [47]:
#lancement
z1_bis = boucle_v1_bis(vec)
print(np.sum(z1_bis))
272817349.82839215
In [48]:
#temps de traitement
%timeit -r 10 -n 1 boucle_v1_bis(vec)
354 ms ± 13.8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
In [49]:
#boucle sur un vecteur numpy
def boucle_v2(v):
    result = np.empty(v.shape[0])
    for i in range(v.shape[0]):
        result[i] = trans(v[i])
    return result
In [50]:
#lancement
z2 = boucle_v2(vec)
print(np.sum(z2))
272817349.82839215
In [51]:
#temps de traitement
%timeit -r 10 -n 1 boucle_v2(vec)
385 ms ± 8.37 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)
In [52]:
#boucle sur un vecteur
def boucle_v3(v):
    result = np.empty(v.shape[0])
    for i,x in enumerate(v):
        result[i] = trans(x)
    return result
In [53]:
#lancement
z3 = boucle_v3(vec)
print(np.sum(z3))
272817349.82839215
In [54]:
#temps de traitement
%timeit -r 10 -n 1 boucle_v3(vec)
390 ms ± 10.3 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

Vectorisation¶

In [55]:
#fonction de vectorisation
vecfun = np.vectorize(trans)
In [56]:
#application de la fonction
z4 = vecfun(vec)
np.sum(z4)
Out[56]:
272817349.82839215
In [57]:
#temps de traitement
%timeit -r 10 -n 1 vecfun(vec)
234 ms ± 8.25 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

Vectorisation avec Numba¶

In [58]:
#version de numba
import numba
numba.__version__
Out[58]:
'0.60.0'
In [59]:
from numba import njit
#fonction pour transformer une valeur
@njit
def trans_numba(x):
    if (x < 0.1):
        res = 1
    elif (x < 0.3):
        res = x**2
    elif (x < 0.8):
        res = (x+1)*31.5
    else:
        res = 1245
    return res
In [60]:
#fonction de vectorisation
vecfun_numba = np.vectorize(trans_numba)
In [61]:
#application de la fonction
z5 = vecfun_numba(vec)
np.sum(z5)
Out[61]:
272817349.82839215
In [62]:
#temps de traitement
%timeit -r 10 -n 1 vecfun_numba(vec)
197 ms ± 7.5 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

Vectorisation avec Numba + xarray¶

In [63]:
from numba import vectorize, float64
#nouvelle directive de compilation pour la vectorisation
@vectorize([float64(float64)])
def trans_numba_bis(x):
    if (x < 0.1):
        res = 1
    elif (x < 0.3):
        res = x**2
    elif (x < 0.8):
        res = (x+1)*31.5
    else:
        res = 1245
    return res
In [64]:
#version de xarray
import xarray as xr
xr.__version__
Out[64]:
'2023.6.0'
In [65]:
#appliquer la fonction trans() aux valeurs du vecteur
import xarray as xr
z6 = xr.apply_ufunc(trans_numba_bis,vec)
np.sum(z6)
Out[65]:
272817349.82839215
In [66]:
#temps de traitement
%timeit -r 10 -n 1 xr.apply_ufunc(trans_numba_bis,vec)
5.49 ms ± 1.35 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

Indexation booléene¶

In [67]:
#ré-écrire la fonction trans
def index_bool(v):
    result = np.zeros(v.shape[0])
    result[v < 0.1] = 1
    result[(v >= 0.1) & (v < 0.3)] = v[(v >= 0.1) & (v < 0.3)]**2
    result[(v >= 0.3) & (v < 0.8)] = (v[(v >= 0.3) & (v < 0.8)] + 1) * 31.5
    result[v >= 0.8] = 1245
    return result
In [68]:
#tester
z7 = index_bool(vec)
np.sum(z7)
Out[68]:
272817349.82839215
In [69]:
#temps de traitement
%timeit -r 10 -n 1 index_bool(vec)
48.3 ms ± 3.15 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)