Como faço para calcular a derivada usando o Numpy?

91

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 ...

DrStrangeLove
fonte
5
Você precisa usar Sympy: sympy.org/en/index.html Numpy é uma biblioteca de computação numérica para Python
prrao
Alternativamente, você quer um método para estimar o valor numérico da derivada? Para isso, você pode usar um método de diferenças finitas, mas tenha em mente que eles tendem a ser terrivelmente barulhentos.
Henry Gomersall

Respostas:

142

Você tem quatro opções

  1. Diferenças Finitas
  2. Derivativos Automáticos
  3. Diferenciação Simbólica
  4. Calcule as derivadas manualmente.

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 à numpysintaxe, 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]: 2x

In [7]: f = lambdify(x, yprime, 'numpy')
In [8]: f(np.ones(5))
Out[8]: [ 2.  2.  2.  2.  2.]
MRocklin
fonte
Desculpe, se isso parece estúpido, quais são as diferenças entre 3. Diferenciação simbólica e 4. diferenciação manual ??
DrStrangeLove
11
Quando eu disse "diferenciação simbólica", pretendia sugerir que o processo era controlado por um computador. Nos princípios 3 e 4 diferem apenas por quem faz o trabalho, o computador ou o programador. 3 é preferível a 4 devido à consistência, escalabilidade e preguiça. 4 é necessário se 3 não conseguir encontrar uma solução.
MRocklin
4
Na linha 7 fizemos f, uma função que calcula a derivada de y wrt x. Em 8, aplicamos esta função derivada a um vetor de todos os uns e obtemos o vetor de todos os dois. Isso ocorre porque, conforme declarado na linha 6, yprime = 2 * x.
MRocklin
Apenas para fins de integridade, você também pode fazer diferenciação por integração (consulte a fórmula integral de Cauchy), ela é implementada, por exemplo, em mpmath(não tenho certeza, porém, do que eles fazem exatamente).
DerWeh
Existe uma maneira fácil de fazer diferenças finitas em numpy sem implementá-lo sozinho? por exemplo, eu quero encontrar o gradiente de uma função em pontos predefinidos.
Alex
41

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).

Sparkler
fonte
2
E se dx não for constante?
weberc2 01 de
3
@ weberc2, nesse caso você deve dividir um vetor por outro, mas tratar as arestas separadamente com derivadas para frente e para trás manualmente.
Sparkler
2
Ou você pode interpolar y com um dx constante e calcular o gradiente.
IceArdor
@Sparkler Obrigado por sua sugestão. Se eu puder fazer 2 pequenas perguntas, (i) por que passamos dxpara em numpy.gradientvez de x? (ii) Podemos também fazer a sua última linha da seguinte forma dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304
2
A partir de v1.13, o espaçamento não uniforme pode ser especificado usando uma matriz como o segundo argumento. Veja a seção de exemplos desta página .
Nathaniel Jones
26

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 xde abscissas com uma matriz correspondente yde valores de função, você pode calcular aproximações de derivadas com

numpy.diff(y) / numpy.diff(x)
Sven Marnach
fonte
2
'Calcular derivadas numéricas para casos mais gerais é fácil' - discordo, calcular derivadas numéricas para casos gerais é bastante difícil. Você acabou de escolher funções bem comportadas.
High Performance Mark
o que significa 2 após >>> imprimir p ?? (na 2ª linha)
DrStrangeLove
@DrStrangeLove: Esse é o expoente. Destina-se a simular notação matemática.
Sven Marnach
@SvenMarnach é o expoente máximo ?? ou o que?? Por que ele acha que o expoente é 2 ??
Inserimos
2
@DrStrangeLove: A saída deve ser lida como 1 * x**2 + 1. Eles colocam o 2na linha acima porque é um expoente. Olhe à distância.
Sven Marnach
14

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
yellow01
fonte
8

Vou jogar outro método na pilha ...

scipy.interpolateOs 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)
flutefreak7
fonte
acabei de tentar fazer isso, continuo recebendo erros desta função AxisError: o eixo -1 está fora dos limites para a matriz de dimensão 0 e não vejo nenhuma resposta para isso na comunidade, qualquer ajuda?
Ayan Mitra
Poste seu problema como uma nova pergunta e crie um link para ela aqui. Provavelmente, será necessário fornecer um exemplo que faça com que seu erro ocorra. Os erros que tenho com funções interp geralmente ocorrem porque os dados não estão bem formados ao entrar - como valores repetidos, número incorreto de dimensões, um dos arrays está acidentalmente vazio, os dados não são classificados em x ou quando classificados não é um função válida, etc. É possível que scipy esteja chamando numpy incorretamente, mas é muito improvável. Verifique x.shape e y.shape. Veja se np.interp () funciona - pode fornecer um erro mais útil se não funcionar.
flutefreak7
5

Para calcular gradientes, a comunidade de aprendizado de máquina usa Autograd:

" Calcula com eficiência derivados de código numpy. "

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.

Gordon Schücker
fonte
Oi, esta função pode ser usada para diferenciar entre duas colunas de dados numericamente, fornecendo o comprimento da etapa? obrigado
Ayan Mitra
3

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
Fraxel
fonte
2

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
johnson
fonte