Jak obliczyć pochodną za pomocą Numpy?

96

Na przykład, jak obliczyć pochodną funkcji

y = x 2 +1

używając numpy?

Powiedzmy, że chcę mieć wartość pochodnej przy x = 5 ...

Dr StrangeLove
źródło
5
Musisz użyć Sympy: sympy.org/en/index.html Numpy to biblioteka obliczeń numerycznych dla Pythona
prrao
Alternatywnie, czy potrzebujesz metody szacowania wartości liczbowej instrumentu pochodnego? W tym celu możesz użyć metody różnic skończonych, ale pamiętaj, że zwykle są one strasznie hałaśliwe.
Henry Gomersall

Odpowiedzi:

148

Masz cztery opcje

  1. Skończone różnice
  2. Automatyczne instrumenty pochodne
  3. Zróżnicowanie symboliczne
  4. Ręczne obliczanie pochodnych.

Skończone różnice nie wymagają zewnętrznych narzędzi, ale są podatne na błędy numeryczne, a jeśli jesteś w sytuacji wielowymiarowej, może to chwilę potrwać.

Zróżnicowanie symboliczne jest idealne, jeśli problem jest wystarczająco prosty. W dzisiejszych czasach metody symboliczne stają się coraz mocniejsze. SymPy to doskonały projekt do tego, który dobrze integruje się z NumPy. Spójrz na funkcje autowrap lub lambdify lub przeczytaj wpis na blogu Jensena dotyczący podobnego pytania .

Automatyczne pochodne są bardzo fajne, nie są podatne na błędy numeryczne, ale wymagają dodatkowych bibliotek (Google do tego jest kilka dobrych opcji). Jest to najbardziej solidny, ale także najbardziej wyrafinowany / trudny do skonfigurowania wybór. Jeśli możesz ograniczyć się do numpyskładni, Theano może być dobrym wyborem.

Oto przykład użycia 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.]
MRocklin
źródło
Przepraszam, jeśli wydaje się to głupie, jakie są różnice między 3. różnicowaniem symbolicznym a różnicowaniem 4. ręcznym?
DrStrangeLove
11
Kiedy powiedziałem „symboliczne zróżnicowanie”, zamierzałem zasugerować, że procesem zajmuje się komputer. W zasadzie 3 i 4 różnią się tylko tym, kto wykonuje pracę, komputerem czy programistą. 3 jest preferowane zamiast 4 ze względu na spójność, skalowalność i lenistwo. 4 jest konieczne, jeśli 3 nie znajdzie rozwiązania.
MRocklin
4
W linii 7. utworzyliśmy funkcję f, która oblicza pochodną y wrt x. W 8 stosujemy tę pochodną funkcję do wektora wszystkich jedynek i otrzymujemy wektor wszystkich dwójek. Dzieje się tak, ponieważ, jak stwierdzono w wierszu 6, yprime = 2 * x.
MRocklin,
Dla zupełności można też dokonać różniczkowania przez całkowanie (patrz wzór całkowy Cauchy'ego), jest ono realizowane np. W mpmath(nie wiem jednak, co dokładnie robią).
DerWeh
Czy istnieje łatwy sposób na zrobienie skończonych różnic w numpy bez jego samodzielnego wdrażania? np. chcę znaleźć gradient funkcji w określonych punktach.
Alex
43

Najprostszym sposobem, jaki przychodzi mi do głowy, jest użycie funkcji gradientu numpy :

x = numpy.linspace(0,10,1000)
dx = x[1]-x[0]
y = x**2 + 1
dydx = numpy.gradient(y, dx)

W ten sposób dydx zostanie obliczony przy użyciu różnic centralnych i będzie miał taką samą długość jak y, w przeciwieństwie do numpy.diff, który używa różnic do przodu i zwróci wektor rozmiaru (n-1).

Brylant
źródło
2
A co jeśli dx nie jest stałe?
weberc2
3
@ weberc2, w takim przypadku powinieneś podzielić jeden wektor przez drugi, ale ręcznie traktować krawędzie osobno za pomocą pochodnych do przodu i do tyłu.
Sparkler
2
Lub możesz interpolować y ze stałą dx, a następnie obliczyć gradient.
IceArdor
@Sparkler Dzięki za sugestię. Jeśli mogę zadać 2 małe pytania, (i) dlaczego przechodzimy dxdo numpy.gradientzamiast x? (ii) Czy możemy również wykonać ostatnią linię w następujący sposób dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304
2
Od wersji 1.13 niejednolite odstępy można określić, używając tablicy jako drugiego argumentu. Zobacz sekcję Przykłady na tej stronie .
Nathaniel Jones
28

NumPy nie zapewnia ogólnej funkcjonalności obliczania pochodnych. Może jednak obsługiwać prosty, specjalny przypadek wielomianów:

>>> p = numpy.poly1d([1, 0, 1])
>>> print p
   2
1 x + 1
>>> q = p.deriv()
>>> print q
2 x
>>> q(5)
10

Jeśli chcesz obliczyć pochodną numerycznie, możesz uciec od używania ilorazów centralnych różnic dla większości zastosowań. Dla pochodnej w jednym punkcie wzór wyglądałby mniej więcej tak

x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)

jeśli masz tablicę xodciętych z odpowiednią tablicą ywartości funkcji, możesz obliczyć przybliżenia pochodnych za pomocą

numpy.diff(y) / numpy.diff(x)
Sven Marnach
źródło
2
„Obliczanie pochodnych numerycznych dla przypadku bardziej ogólnego jest łatwe” - nie zgadzam się, obliczanie pochodnych numerycznych dla przypadków ogólnych jest dość trudne. Po prostu wybrałeś ładnie działające funkcje.
Znak wysokiej wydajności
co oznacza 2 po >>> print p ?? (w drugiej linii)
DrStrangeLove
@DrStrangeLove: To jest wykładnik. Ma na celu symulowanie notacji matematycznej.
Sven Marnach
@SvenMarnach czy to maksymalny wykładnik ?? albo co?? Dlaczego myśli, że wykładnik wynosi 2? Wprowadziliśmy tylko współczynniki ...
DrStrangeLove
2
@DrStrangeLove: Wyjście powinno być odczytywane jako 1 * x**2 + 1. W 2powyższym wierszu umieścili, ponieważ jest to wykładnik. Spójrz na to z daleka.
Sven Marnach
15

Zakładając, że chcesz użyć numpy, możesz numerycznie obliczyć pochodną funkcji w dowolnym momencie, używając definicji Rygorystycznej :

def d_fun(x):
    h = 1e-5 #in theory h is an infinitesimal
    return (fun(x+h)-fun(x))/h

Aby uzyskać lepsze wyniki, możesz również użyć pochodnej symetrycznej :

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

Korzystając z Twojego przykładu, pełny kod powinien wyglądać mniej więcej tak:

def fun(x):
    return x**2 + 1

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

Teraz możesz numerycznie znaleźć pochodną pod adresem x=5:

In [1]: d_fun(5)
Out[1]: 9.999999999621423
fabda01
źródło
8

Rzucę inną metodę na stos ...

scipy.interpolateWiele interpolujących splajnów może zapewnić pochodne. Tak więc, używając liniowego splajnu ( k=1), pochodna splajnu (przy użyciu derivative()metody) powinna być równoważna różnicy w przód. Nie jestem do końca pewien, ale uważam, że użycie pochodnej sześciennej splajnu byłoby podobne do wyśrodkowanej pochodnej różnicy, ponieważ używa wartości przed i po do skonstruowania sześciennego splajnu.

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
źródło
właśnie próbowałem tego, wciąż otrzymuję błędy z tej funkcji AxisError: oś -1 jest poza zakresem dla tablicy wymiaru 0 i nie widzę żadnych odpowiedzi na to również w społeczności, jakaś pomoc?
Ayan Mitra
Opublikuj swój problem jako nowe pytanie i łącze do niego tutaj. Prawdopodobnie potrzebne będzie podanie przykładu powodującego wystąpienie błędu. Błędy, które mam z funkcjami interp są zwykle spowodowane tym, że dane nie są dobrze uformowane - jak powtarzające się wartości, zła liczba wymiarów, jedna z tablic jest przypadkowo pusta, dane nie są sortowane względem x lub gdy posortowane poprawna funkcja itp. Możliwe, że scipy wywołuje numpy niepoprawnie, ale jest bardzo mało prawdopodobne. Sprawdź x.shape i y.shape. Sprawdź, czy działa np.interp () - może dostarczyć bardziej pomocnego błędu, jeśli nie.
flutefreak7
6

Aby obliczyć gradienty, społeczność uczenia maszynowego używa Autograd:

Efektywnie oblicza pochodne kodu numpy ”.

Żeby zainstalować:

pip install autograd

Oto przykład:

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

Może również obliczać gradienty funkcji złożonych, np. Funkcji wielowymiarowych.

Gordon Schücker
źródło
Cześć, czy ta funkcja może służyć do numerycznego rozróżniania dwóch kolumn danych poprzez podanie długości kroku? dzięki
Ayan Mitra
3

W zależności od wymaganego poziomu dokładności możesz to rozwiązać samodzielnie, korzystając z prostego dowodu różnicowania:

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

nie możemy właściwie przyjąć granicy gradientu, ale to trochę zabawne. Musisz jednak uważać, ponieważ

>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0
fraxel
źródło