Como faço para calcular a derivada de uma função, por exemplo
y = x 2 +1
usando numpy
?
Digamos que eu queira o valor da derivada em x = 5 ...
Como faço para calcular a derivada de uma função, por exemplo
y = x 2 +1
usando numpy
?
Digamos que eu queira o valor da derivada em x = 5 ...
Respostas:
Você tem quatro opções
Diferenças finitas não requerem ferramentas externas, mas estão sujeitas a erros numéricos e, se você estiver em uma situação multivariada, pode demorar um pouco.
A diferenciação simbólica é ideal se o seu problema for simples o suficiente. Os métodos simbólicos estão ficando bastante robustos atualmente. SymPy é um excelente projeto para isso que se integra bem com o NumPy. Veja as funções autowrap ou lambdify ou confira a postagem do blog de Jensen sobre uma questão semelhante .
Derivados automáticos são muito legais, não estão sujeitos a erros numéricos, mas requerem algumas bibliotecas adicionais (google para isso, existem algumas boas opções). Esta é a escolha mais robusta, mas também a mais sofisticada / difícil de configurar. Se você está bem restringindo-se à numpy
sintaxe, Theano pode ser uma boa escolha.
Aqui está um exemplo usando 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.]
mpmath
(não tenho certeza, porém, do que eles fazem exatamente).
A maneira mais direta que consigo pensar é usando a função gradiente do numpy :
x = numpy.linspace(0,10,1000)
dx = x[1]-x[0]
y = x**2 + 1
dydx = numpy.gradient(y, dx)
Dessa forma, dydx será calculado usando diferenças centrais e terá o mesmo comprimento que y, ao contrário de numpy.diff, que usa diferenças diretas e retornará o vetor de tamanho (n-1).
dx
para em numpy.gradient
vez de x
? (ii) Podemos também fazer a sua última linha da seguinte forma dydx = numpy.gradient(y, numpy.gradient(x))
:?
NumPy não fornece funcionalidade geral para calcular derivados. Ele pode lidar com o caso especial simples de polinômios, no entanto:
>>> p = numpy.poly1d([1, 0, 1])
>>> print p
2
1 x + 1
>>> q = p.deriv()
>>> print q
2 x
>>> q(5)
10
Se você deseja calcular a derivada numericamente, pode usar os quocientes de diferença centrais para a grande maioria das aplicações. Para a derivada em um único ponto, a fórmula seria algo como
x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)
se você tem uma matriz x
de abscissas com uma matriz correspondente y
de valores de função, você pode calcular aproximações de derivadas com
numpy.diff(y) / numpy.diff(x)
1 * x**2 + 1
. Eles colocam o 2
na linha acima porque é um expoente. Olhe à distância.
Supondo que você queira usar numpy
, você pode calcular numericamente a derivada de uma função em qualquer ponto usando a definição Rigorous :
def d_fun(x):
h = 1e-5 #in theory h is an infinitesimal
return (fun(x+h)-fun(x))/h
Você também pode usar a derivada simétrica para obter melhores resultados:
def d_fun(x):
h = 1e-5
return (fun(x+h)-fun(x-h))/(2*h)
Usando seu exemplo, o código completo deve ser semelhante a:
def fun(x):
return x**2 + 1
def d_fun(x):
h = 1e-5
return (fun(x+h)-fun(x-h))/(2*h)
Agora, você pode encontrar numericamente a derivada em x=5
:
In [1]: d_fun(5)
Out[1]: 9.999999999621423
Vou jogar outro método na pilha ...
scipy.interpolate
Os muitos splines de interpolação do são capazes de fornecer derivadas. Portanto, usando um spline linear ( k=1
), a derivada do spline (usando o derivative()
método) deve ser equivalente a uma diferença direta. Não tenho certeza, mas acredito que usar uma derivada de spline cúbica seria semelhante a uma derivada de diferença centrada, pois usa valores anteriores e posteriores para construir a spline cúbica.
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)
Para calcular gradientes, a comunidade de aprendizado de máquina usa Autograd:
Para instalar:
pip install autograd
Aqui está um exemplo:
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))
Ele também pode calcular gradientes de funções complexas, por exemplo, funções multivariadas.
Dependendo do nível de precisão que você precisa, você mesmo pode resolver isso usando a prova simples de diferenciação:
>>> (((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
não podemos realmente pegar o limite do gradiente, mas é divertido. Você tem que ter cuidado porque
>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0
Você pode usar scipy
, o que é bastante simples:
scipy.misc.derivative(func, x0, dx=1.0, n=1, args=(), order=3)
Encontre a enésima derivada de uma função em um ponto.
No seu caso:
from scipy.misc import derivative
def f(x):
return x**2 + 1
derivative(f, 5, dx=1e-6)
# 10.00000000139778