Skip to article frontmatterSkip to article content

contenu de ce notebook (sauter si déjà acquis)

# on importe la librairie numpy
import numpy as np
from matplotlib import pyplot as plt

qu’est-ce que la vectorisation ?

# pour comparer les choses comparables
import math

n = 1_000_000
x = np.linspace(0, 2*np.pi, n)
%%timeit

# la bonne façon
np.sin(x)               # np.sin appliquée au tableau x
153 ms ± 10.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit

# la mauvaise façon
for e in x:             # une boucle for sur un tableau numpy
                        # c'est toujours une mauvaise idée
    math.sin(e)
670 ms ± 179 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

dessiner un cercle de rayon r

exercice

Dessinez un cercle de rayon r

indices

  1. x=rsin(θ)x = r\, sin(\theta)
    y=rcos(θ)y = r\, cos(\theta)
    avec θ\theta variant de 0 à 2π2\pi
  2. si votre cercle apparaît elliptique, c’est que les échelles de vos axes diffèrent
    demandez à ce qu’elles soient égales avec plt.axis('equal')
# votre code

calculer une fonction polynomiale

exercice

  1. faites une fonction qui retourne le calcul d’un polynome
    par exemple x3+2x25x+1x^3 + 2x^2 -5x +1
    (puissance: ** ou np.power)

  2. appliquez la directement à un np.ndarray (sans faire de for) qu’obtenez-vous en retour ?

  3. tracez la courbe de la fonction

# votre code ici
def scalar_function(x):
    pass

les ufunc

qu’est-ce qu’une ufunc


quelles sont les fonctions vectorisées ?


savoir si une fonction est une ufunc

# essayez !
np.power
<ufunc 'power'>

exercice

  1. la fonction numpy.abs est-elle une ufunc ?

  2. la fonction abs de Python est-elle une ufunc ?

# votre code

pour vectoriser une fonction

exercice

  1. écrivez une fonction qui calcule la valeur absolue d’un scalaire x absolute(x)
    on s’interdit donc, dans cet exercice, d’utiliser des fonctions de numpy, ni la fonction builtin abs de Python
  2. testez votre fonction sur des scalaires
  3. créez un np.ndarray de scalaires et appliquez-lui la fonction
  4. que se passe-t-il ?
# votre code ici

problème de la fonction absolute

mais vous ne voulez rien de tout cela !

# le code
@np.vectorize
def absolute (x):
    if x >= 0:
        return x
    return -x
# le code

tab = np.array([10, -30, 56.5])
absolute(tab)
array([10. , 30. , 56.5])
# et d'ailleurs à titre anecdotique:
# elle fonctionne aussi sur une `list` `python`

absolute([-10, -20, 30])
array([10, 20, 30])

note sur les performances

X = np.linspace(-10, 10, 10_000)
# la version avec np.vectorize n'est pas spécialement efficace

@np.vectorize
def x2_x3_vec(x):
    return x**2 if x < 0 else x**3

%timeit x2_x3_vec(X)
15.5 ms ± 1.46 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
# on peut faire beaucoup mieux avec ce code
# le défaut c'est qu'on calcule 3 tableaux de la même taille 
# en plus du tableau résultat

def x2_x3_where(x):
    return np.where( x<0, x**2, x**3)

%timeit x2_x3_where(X)
729 μs ± 91.9 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

pour les avancés ou les rapides

résultats intermédiaires lors de calculs


une solution aux tableaux intermédiaires

le code ci-dessous

def trigo_function_compact (x):
    return 4*np.exp(np.cos(x))**2
plt.plot(trigo_function_compact(np.linspace(0, 2*np.pi, 1000)));
<Figure size 640x480 with 1 Axes>
def trigo_function_developpee (x):
    int_1 = np.cos(x)
    int_2 = np.exp(int_1)
    int_3 = np.power(int_2, 2)
    result = 4*int_3
    return result
def trigo_function_developpee_out (x):
    result = np.cos(x)      # il m'en faut bien un pour le résultat !
    np.exp(result, out=result)
    np.power(result, 2, out=result)
    np.multiply(4, result, out=result)
    return result
plt.plot(trigo_function_developpee_out(np.linspace(0, 2*np.pi, 1000)));
<Figure size 640x480 with 1 Axes>

temps d’exécution de l’élévation d’un tableau au carré - avancé ou rapide

exercice

  1. créez un tableau numpy des 10000 premiers entiers avec numpy.arange
# votre code
  1. calculez le temps d’exécution de l’élévation au carré des éléments

    • a. avec un for-python
    • b. avec une compréhension Python
    • c. de manière vectorisée avec **2
    • d. de manière vectorisée avec np.power
    • e. de manière vectorisée avec np.square
# votre code
  1. quelles sont les manières de faire les plus rapides ?
# votre code
  1. utilisez np.vectorize pour décorer votre fonction 2.c; que constatez-vous ?
# votre code