Comment calculer la dérivée d'une fonction, par exemple
y = x2+1
en utilisant numpy
?
Disons que je veux la valeur de la dérivée à x = 5 ...
Vous avez quatre options
Les différences finies ne nécessitent aucun outil externe, mais sont sujettes aux erreurs numériques et, si vous êtes dans une situation à plusieurs variables, peuvent prendre un certain temps.
La différenciation symbolique est idéale si votre problème est assez simple. Les méthodes symboliques deviennent assez robustes ces jours-ci. SymPy est un excellent projet pour cela qui s'intègre bien à NumPy. Regardez les fonctions autowrap ou lambdify ou consultez l'article de Jensen à propos d'une question similaire .
Les dérivées automatiques sont très chouettes, ne sont pas sujettes aux erreurs numériques, mais nécessitent quelques bibliothèques supplémentaires (Google pour cela, il existe quelques bonnes options). C'est le choix le plus robuste mais aussi le plus sophistiqué/difficile à mettre en place. Si vous vous en tenez à vous limiter à la syntaxe numpy
, alors Theano peut constituer un bon choix.
Voici un exemple utilisant SymPy
In [1]: from sympy import *
In [2]: import numpy as np
In [3]: x = Symbol('x')
In [4]: y = x**2 + 1
In [5]: yprime = y.diff(x)
In [6]: yprime
Out[6]: 2⋅x
In [7]: f = lambdify(x, yprime, 'numpy')
In [8]: f(np.ones(5))
Out[8]: [ 2. 2. 2. 2. 2.]
Le moyen le plus simple auquel je puisse penser est d'utiliser fonction de gradient de numpy :
x = numpy.linspace(0,10,1000)
dx = x[1]-x[0]
y = x**2 + 1
dydx = numpy.gradient(y, dx)
De cette façon, dydx sera calculé en utilisant des différences centrales et aura la même longueur que y, contrairement à numpy.diff, qui utilise des différences en aval et retournera un vecteur de taille (n-1).
NumPy ne fournit pas de fonctionnalité générale pour calculer des dérivés. Il peut cependant gérer le cas particulier simple des polynômes:
>>> p = numpy.poly1d([1, 0, 1])
>>> print p
2
1 x + 1
>>> q = p.deriv()
>>> print q
2 x
>>> q(5)
10
Si vous souhaitez calculer la dérivée numériquement, vous pouvez vous en tirer en utilisant des quotients de différence centraux pour la grande majorité des applications. Pour la dérivée en un seul point, la formule serait quelque chose comme
x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)
si vous avez un tableau x
d'abscisse avec un tableau correspondant y
de valeurs de fonction, vous pouvez calculer des approximations de dérivées avec
numpy.diff(y) / numpy.diff(x)
En supposant que vous souhaitiez utiliser numpy
, vous pouvez calculer numériquement la dérivée d’une fonction à n’importe quel point à l’aide de Définition rigoureuse :
def d_fun(x):
h = 1e-5 #in theory h is an infinitesimal
return (fun(x+h)-fun(x))/h
Vous pouvez également utiliser le dérivé symétrique pour de meilleurs résultats:
def d_fun(x):
h = 1e-5
return (fun(x+h)-fun(x-h))/(2*h)
En utilisant votre exemple, le code complet devrait ressembler à ceci:
def fun(x):
return x**2 + 1
def d_fun(x):
h = 1e-5
return (fun(x+h)-fun(x-h))/(2*h)
Maintenant, vous pouvez numériquement trouver la dérivée en x=5
:
In [1]: d_fun(5)
Out[1]: 9.999999999621423
Je vais jeter une autre méthode sur la pile ...
Les nombreuses splines d'interpolation de scipy.interpolate
sont capables de fournir des dérivés. Ainsi, en utilisant une spline linéaire (k=1
), la dérivée de la spline (à l'aide de la méthode derivative()
) devrait être équivalente à une différence en avant. Je n'en suis pas tout à fait sûr, mais je pense que l'utilisation d'un dérivé de spline cubique serait similaire à un dérivé de différence centrée, car elle utilise les valeurs d'avant et d'après pour construire la spline cubique.
from scipy.interpolate import InterpolatedUnivariateSpline
# Get a function that evaluates the linear spline at any x
f = InterpolatedUnivariateSpline(x, y, k=1)
# Get a function that evaluates the derivative of the linear spline at any x
dfdx = f.derivative()
# Evaluate the derivative dydx at each x location...
dydx = dfdx(x)
En fonction du niveau de précision requis, vous pouvez résoudre le problème vous-même en utilisant la simple preuve de différenciation:
>>> (((5 + 0.1) ** 2 + 1) - ((5) ** 2 + 1)) / 0.1
10.09999999999998
>>> (((5 + 0.01) ** 2 + 1) - ((5) ** 2 + 1)) / 0.01
10.009999999999764
>>> (((5 + 0.0000000001) ** 2 + 1) - ((5) ** 2 + 1)) / 0.0000000001
10.00000082740371
nous ne pouvons pas réellement prendre la limite du gradient, mais c'est un peu amusant. Tu dois faire attention cependant parce que
>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0
Pour calculer les gradients, la communauté de l'apprentissage automatique utilise Autograd:
À installer:
pip install autograd
Voici un exemple:
import autograd.numpy as np
from autograd import grad
def fct(x):
y = x**2+1
return y
grad_fct = grad(fct)
print(grad_fct(1.0))
Il peut également calculer des gradients de fonctions complexes, par exemple. fonctions multivariées.