6.17. Solveurs et nombres aléatoires#
Lorsque la fonction étudiée est définie par du code Python plutôt que par un tampon d’échantillons, une autre famille d’outils est le bon choix : où se trouve la racine de la fonction, son minimum, son intégrale sur un intervalle donné ? Les sous-modules scipy.integrate et scipy.optimize couvrent ce travail. Chaque algorithme rappelle la fonction Python fournie par l’utilisateur, de sorte que le coût par itération est plus élevé qu’une réduction sur tampon ; la commodité réside dans le fait de ne pas avoir à écrire le solveur.
Le sous-module scipy.special couvre les fonctions spéciales statistiques (fonction d’erreur, gamma) qui interviennent lors du calcul de la fonction de répartition (CDF, la probabilité qu’un échantillon soit au plus égal à une valeur donnée) ou de la fonction de densité de probabilité (PDF, la vraisemblance relative à une valeur donnée) d’une distribution de probabilité. numpy.random couvre le générateur pseudo-aléatoire pour le tramage, la simulation et les données de test synthétiques.
6.17.1. Intégration numérique d’une fonction appelable#
Lorsque l’intégrande est une fonction Python plutôt qu’un tampon d’échantillons, scipy.integrate expose quatre algorithmes de quadrature :
quad()– Gauss-Kronrod adaptatif. Le bon choix par défaut pour les intégrandes lisses. Renvoie(value, error).romberg()– Romberg / Newton-Cotes classique. Renvoie un unique flottant. Déprécié en amont ; inclus pour compatibilité.simpson()– règle de Simpson adaptative. Renvoie un unique flottant.tanhsinh()– quadrature double-exponentielle. À utiliser lorsque l’intégrande présente des singularités aux bornes ou une limite infinie. Renvoie(value, error).
L’intégrale gaussienne évaluée avec la règle double-exponentielle (tanhsinh)
from math import exp
from math import pi
from math import sqrt
from ulab import numpy as np
from ulab import scipy as sp
f = lambda x: exp(-x * x)
value, err = sp.integrate.tanhsinh(f, -np.inf, np.inf)
print("approx:", value, " exact:", sqrt(pi))
Sortie
approx: 1.7724538... exact: 1.7724538...
6.17.2. Recherche de racine et minimisation#
scipy.optimize couvre trois solveurs classiques à une seule variable. Chaque itération rappelle la fonction Python fournie par l’utilisateur, de sorte que le gain de vitesse par rapport à un solveur en Python pur est modeste (environ 2x) ; la commodité réside dans le fait de ne pas avoir à écrire le solveur.
bisect()– trouve une racine defsur[a, b]en divisant l’intervalle par deux.f(a)etf(b)doivent avoir des signes opposésdef f(x): return x * x - 1 sp.optimize.bisect(f, 0, 4) # ~1.0
newton()– trouve une racine par itération de la sécante / Newton-Raphsondef f(x): return x * x * x - 2.0 sp.optimize.newton(f, 3., tol=0.001, rtol=0.01) # ~1.260
fmin()– trouve un minimum local par la méthode du simplexe descendant (Nelder-Mead)def f(x): return (x - 1) ** 2 - 1 sp.optimize.fmin(f, 3.0) # ~1.0
La portée à une seule variable suffit pour la plupart des optimisations côté caméra – une constante de calibration d’un capteur, le gain qui maximise une mesure de contraste, le seuil où la bimodalité d’un histogramme est la plus marquée. Pour les problèmes à plusieurs variables, la bonne réponse consiste généralement à reformuler le problème comme une petite résolution d’algèbre linéaire plutôt que de recourir à un optimiseur non linéaire général.
6.17.3. Fonctions spéciales#
scipy.special expose une poignée de fonctions statistiques et de probabilité qui se comportent comme des fonctions universelles – elles acceptent un scalaire, un itérable ou un ndarray et renvoient un ndarray de flottants
x = np.linspace(0, 4, num=8)
sp.special.erf(x) # error function
sp.special.erfc(x) # complementary error function
sp.special.gamma(x + 1) # gamma function
sp.special.gammaln(x + 1) # log-gamma function
La fonction d’erreur et son complément apparaissent dans la CDF d’une gaussienne – l’application de prédilection pour convertir entre un score z mesuré et une probabilité, ou pour calculer l’intégrale de queue d’une distribution normale. Les fonctions gamma et log-gamma apparaissent dans les calculs bêta / khi-deux / student-t ; gammaln est la forme numériquement stable pour les grands arguments où gamma lui-même déborderait.
6.17.4. Nombres aléatoires#
numpy.random fournit une classe Generator qui tire des échantillons de distributions courantes. Le générateur est à état : chaque appel fait avancer son état interne, de sorte que des appels consécutifs renvoient des échantillons indépendants
from ulab import numpy as np
rng = np.random.Generator(seed=42)
rng.random(size=5) # 5 uniform [0.0, 1.0) samples
rng.uniform(low=-1.0, high=1.0, size=10)
rng.normal(loc=0.0, scale=1.0, size=(2, 4))
Le dtype de sortie est toujours float. size= accepte un entier (sortie à une dimension) ou un uplet (sortie à n dimensions) ; lorsqu’il est omis, un unique flottant Python est renvoyé.
Le générateur convient à la simulation, au tramage, aux données de test synthétiques et à toute autre application où une robustesse cryptographique n’est pas requise. Il n’est pas adapté aux clés ou aux jetons ; utilisez pour cela la source aléatoire du système via os.
6.17.5. Disponibilité à la compilation#
La présence effective de chaque sous-module dépend de la façon dont la caméra a été compilée. scipy.optimize et scipy.special ne sont pas activés sur toutes les caméras ; appeler une fonction que la caméra n’inclut pas lève AttributeError. dir(sp), dir(sp.optimize), dir(np.random) et consorts indiquent ce qui est disponible sur la caméra ciblée.