Bagaimana cara menghitung turunan menggunakan Numpy?

96

Bagaimana cara menghitung turunan suatu fungsi, misalnya

y = x 2 +1

menggunakan numpy ?

Katakanlah, saya ingin nilai turunannya pada x = 5 ...

DrStrangeLove
sumber
5
Anda perlu menggunakan Sympy: sympy.org/en/index.html Numpy adalah pustaka komputasi numerik untuk Python
prrao
Atau, apakah Anda menginginkan metode untuk memperkirakan nilai numerik dari turunan? Untuk ini, Anda dapat menggunakan metode perbedaan hingga, tetapi perlu diingat bahwa metode tersebut cenderung sangat berisik.
Henry Gomersall

Jawaban:

148

Anda memiliki empat opsi

  1. Perbedaan Hingga
  2. Derivatif Otomatis
  3. Diferensiasi Simbolik
  4. Hitung turunan dengan tangan.

Perbedaan terbatas tidak memerlukan alat eksternal tetapi rentan terhadap kesalahan numerik dan, jika Anda berada dalam situasi multivarian, dapat memakan waktu cukup lama.

Diferensiasi simbolik ideal jika masalah Anda cukup sederhana. Metode simbolis semakin kuat belakangan ini. SymPy adalah proyek luar biasa untuk ini yang terintegrasi dengan baik dengan NumPy. Lihat fungsi autowrap atau lambdify atau lihat posting blog Jensen tentang pertanyaan serupa .

Turunan otomatis sangat keren, tidak rentan terhadap kesalahan numerik, tetapi memerlukan beberapa pustaka tambahan (untuk ini google, ada beberapa opsi bagus). Ini adalah pilihan yang paling kuat tetapi juga yang paling canggih / sulit untuk diatur. Jika Anda baik-baik saja membatasi diri Anda pada numpysintaks, maka Theano mungkin pilihan yang baik.

Berikut ini contoh penggunaan 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
sumber
Maaf, jika ini terlihat bodoh, Apa perbedaan antara 3. Diferensiasi Simbolik dan 4. Diferensiasi tangan ??
DrStrangeLove
11
Ketika saya mengatakan "diferensiasi simbolis", saya bermaksud menyiratkan bahwa proses tersebut ditangani oleh komputer. Pada prinsipnya 3 dan 4 hanya berbeda dalam hal siapa yang mengerjakan, komputer atau pemrogramnya. 3 lebih disukai daripada 4 karena konsistensi, skalabilitas, dan kemalasan. 4 diperlukan jika 3 gagal menemukan solusi.
MRocklin
4
Di baris 7 kita membuat f, sebuah fungsi yang menghitung turunan dari y wrt x. Dalam 8 kita menerapkan fungsi turunan ini ke vektor dari semua satu dan mendapatkan vektor dari semua berpasangan. Ini karena, seperti yang dinyatakan pada baris 6, yprime = 2 * x.
MRocklin
Hanya demi kelengkapan, Anda juga dapat melakukan diferensiasi dengan integrasi (lihat rumus integral Cauchy), itu diimplementasikan misalnya di mpmath(tidak yakin apa yang mereka lakukan).
DerWeh
Apakah ada cara mudah untuk melakukan perbedaan terbatas di numpy tanpa menerapkannya sendiri? misalnya saya ingin mencari gradien fungsi pada titik-titik yang telah ditentukan.
Alex
43

Cara paling mudah yang dapat saya pikirkan adalah menggunakan fungsi gradien numpy :

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

Dengan cara ini, dydx akan dihitung menggunakan perbedaan pusat dan akan memiliki panjang yang sama dengan y, tidak seperti numpy.diff, yang menggunakan perbedaan maju dan akan mengembalikan vektor ukuran (n-1).

Sparkler
sumber
2
Bagaimana jika dx tidak konstan?
weberc2
3
@ weberc2, dalam hal ini Anda harus membagi satu vektor dengan vektor lainnya, tetapi perlakukan tepinya secara terpisah dengan turunan maju dan mundur secara manual.
Sparkler
2
Atau Anda dapat menginterpolasi y dengan konstanta dx, lalu menghitung gradiennya.
IceArdor
@Sparkler Terima kasih atas saran Anda. Jika saya boleh mengajukan 2 pertanyaan kecil, (i) mengapa kita lolos dxke numpy.gradientalih-alih x? (ii) Bisakah kita juga melakukan baris terakhir dari Anda sebagai berikut: dydx = numpy.gradient(y, numpy.gradient(x))?
user929304
2
Mulai v1.13, spasi yang tidak seragam dapat ditentukan menggunakan array sebagai argumen kedua. Lihat bagian Contoh di halaman ini .
Nathaniel Jones
28

NumPy tidak menyediakan fungsionalitas umum untuk menghitung turunan. Ia dapat menangani kasus khusus polinomial sederhana namun:

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

Jika Anda ingin menghitung turunan secara numerik, Anda dapat menggunakan kuosien perbedaan pusat untuk sebagian besar aplikasi. Untuk turunan dalam satu titik, rumusnya akan seperti ini

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

jika Anda memiliki larik xabsis dengan larik ynilai fungsi yang sesuai , Anda dapat menghitung perkiraan turunan dengan

numpy.diff(y) / numpy.diff(x)
Sven Marnach
sumber
2
'Menghitung turunan numerik untuk kasus yang lebih umum itu mudah' - Saya mohon berbeda, menghitung turunan numerik untuk kasus umum cukup sulit. Anda baru saja memilih fungsi yang berperilaku baik.
Performa Tinggi Mark
apa artinya 2 setelah >>> print p ?? (pada baris ke-2)
DrStrangeLove
@DrStrangeLove: Itu eksponennya. Ini dimaksudkan untuk mensimulasikan notasi matematika.
Sven Marnach
@Svenarnach apakah itu eksponen maksimum ?? atau apa?? Mengapa menurutnya eksponen adalah 2 ?? Kami hanya
memasukkan
2
@DrStrangeLove: Outputnya seharusnya dibaca sebagai 1 * x**2 + 1. Mereka meletakkan 2di baris di atas karena eksponennya. Lihatlah dari kejauhan.
Sven Marnach
15

Dengan asumsi Anda ingin menggunakan numpy, Anda dapat menghitung turunan suatu fungsi secara numerik pada titik mana pun menggunakan definisi Ketelitian :

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

Anda juga dapat menggunakan turunan Symmetric untuk hasil yang lebih baik:

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

Menggunakan contoh Anda, kode lengkap akan terlihat seperti ini:

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

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

Sekarang, Anda dapat menemukan turunannya secara numerik di x=5:

In [1]: d_fun(5)
Out[1]: 9.999999999621423
fabda01
sumber
8

Saya akan melempar metode lain ke tumpukan ...

scipy.interpolateBanyak splines interpolasi mampu menghasilkan turunan. Jadi, dengan menggunakan spline linier ( k=1), turunan dari spline (menggunakan derivative()metode) harus setara dengan perbedaan maju. Saya tidak sepenuhnya yakin, tapi saya percaya menggunakan turunan spline kubik akan mirip dengan turunan perbedaan terpusat karena menggunakan nilai dari sebelum dan sesudah untuk membuat spline kubik.

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
sumber
baru saja mencoba ini, saya terus mendapatkan kesalahan dari fungsi ini AxisError: sumbu -1 di luar batas untuk array dimensi 0 dan saya juga tidak melihat jawaban untuk ini di komunitas, ada bantuan?
Ayan Mitra
Poskan masalah Anda sebagai pertanyaan baru dan tautkan ke sini. Memberikan contoh yang menyebabkan kesalahan Anda mungkin akan dibutuhkan. Kesalahan yang saya miliki dengan fungsi interp biasanya karena datanya tidak terbentuk dengan baik - seperti nilai yang berulang, jumlah dimensi yang salah, salah satu array tidak sengaja kosong, data tidak diurutkan terhadap x atau ketika diurutkan bukan a fungsi yang valid, dll. Mungkin saja scipy salah memanggil numpy, tetapi sangat tidak mungkin. Centang x.shape dan y.shape. Lihat apakah np.interp () berfungsi - ini mungkin memberikan kesalahan yang lebih berguna jika tidak.
flutefreak7
6

Untuk menghitung gradien, komunitas pembelajaran mesin menggunakan Autograd:

" Menghitung turunan kode numpy secara efisien. "

Untuk memasang:

pip install autograd

Berikut ini contohnya:

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

Ia juga dapat menghitung gradien fungsi kompleks, misalnya fungsi multivariasi.

Gordon Schücker
sumber
Hai dapatkah fungsi ini digunakan untuk membedakan antara dua kolom data secara numerik dengan memberikan panjang langkah? terima kasih
Ayan Mitra
3

Bergantung pada tingkat presisi yang Anda butuhkan, Anda dapat mengerjakannya sendiri, menggunakan bukti diferensiasi sederhana:

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

kita tidak bisa benar-benar mengambil batas gradien, tapi ini agak menyenangkan. Anda harus berhati-hati karena

>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0
fraxel
sumber
2

Anda dapat menggunakan scipy, yang sangat mudah:

scipy.misc.derivative(func, x0, dx=1.0, n=1, args=(), order=3)

Temukan turunan ke-n dari suatu fungsi pada suatu titik.

Dalam kasus Anda:

from scipy.misc import derivative

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

derivative(f, 5, dx=1e-6)
# 10.00000000139778
johnson
sumber