6.11. Réductions¶
Une réduction condense un tableau le long d’un ou plusieurs axes en sommant, en faisant la moyenne, en prenant un minimum, et ainsi de suite. Chaque réduction est un unique appel de bibliothèque sur l’ensemble du tableau, bien plus rapide que la boucle Python équivalente. numpy couvre les plus courantes :
sum()– total de chaque élémentmean()– moyenne arithmétique (somme divisée par le nombre d’éléments)std()– écart-type,ddof=ajuste le diviseur (N - ddof)median()– valeur médiane lorsque les éléments sont triés (50e centile)argmin()/argmax()– l”indice de l’élément minimal ou maximalall()/any()– réductions de valeur de vérité sur des tableaux booléens
6.11.1. Sans le mot-clé axis¶
Appelée sans axis=, une réduction renvoie un scalaire couvrant l’ensemble du tableau
a = np.array([1, 2, 3, 4], dtype=np.float)
np.sum(a) # 10.0
np.mean(a) # 2.5
np.std(a) # 1.118...
np.median(a) # 2.5
b = np.array([40, 10, 30, 20], dtype=np.float)
np.max(b) # 40.0
np.argmax(b) # 0 (index of the maximum)
6.11.2. Avec le mot-clé axis¶
axis= contracte un axe nommé et laisse les autres intacts. Le résultat est un tableau d’un rang inférieur à celui de l’entrée
m = np.arange(12, dtype=np.float).reshape((3, 4))
np.sum(m) # 66.0 - scalar
np.sum(m, axis=0) # length-4 - column sums
np.sum(m, axis=1) # length-3 - row sums
La même règle de forme s’applique à chaque réduction : axis=0 condense le premier axe, axis=1 condense le second, et ainsi de suite. La moyenne / l’écart-type le long d’une ligne, par exemple, s’écrivent np.mean(m, axis=1) et np.std(m, axis=1). Le résultat a la longueur de l”autre axe.
Le mot-clé keepdims=True conserve l’axe contracté en place avec une longueur de 1 au lieu de le supprimer. La distinction importe lorsque le résultat réduit doit être rediffusé contre l’original : keepdims préserve le rang, ce qui maintient les règles de diffusion alignées axe par axe.
Soustraire la moyenne de chaque ligne à cette ligne est l’usage canonique
m = np.arange(12, dtype=np.float).reshape((3, 4))
row_means = np.mean(m, axis=1, keepdims=True)
# row_means has shape (3, 1)
centred = m - row_means
# (3, 4) - (3, 1) -> (3, 4), each row centred on its own mean
Sans keepdims, np.mean(m, axis=1) renvoie un résultat 1-D de forme (3,). La diffusion de (3, 4) - (3,) aligne (3,) comme (1, 3) après l’ajout de rang en tête, ce qui est incompatible avec (3, 4) : les derniers axes ne concordent pas (4 contre 3) et ni l’un ni l’autre n’est 1, donc numpy lève ValueError. keepdims=True est ce qui rend la soustraction valide.
6.11.3. La disposition compte¶
Combinée à la disposition par lignes (row-major) abordée dans Forme et pas (strides), la réduction le long du dernier axe est le cas le moins coûteux. La réduction parcourt le bloc de données dans la direction où il est stocké, sans sauts d’une ligne à l’autre
m = np.arange(2000, dtype=np.float).reshape((2, 1000))
np.sum(m, axis=1) # cheap - long axis is the inner one
np.sum(m, axis=0) # has to jump rows on every step
Lorsque l’application peut choisir la disposition d’un tampon, placez l’axe le plus long en dernier afin que les réductions le long de celui-ci s’exécutent dans la direction rapide.
6.11.4. Itérables en entrée¶
La plupart des réductions acceptent un itérable Python (une list, un range, un tuple) à la place d’un ndarray. Cette commodité coûte quelques microsecondes pour la conversion implicite – ce qui s’additionne vite dans une boucle. Lorsque les mêmes données sont réduites plusieurs fois, construisez le ndarray une seule fois et faites-le circuler.