2012-03-26 92 views
47

如何使用numpy計算函數的導數,例如如何使用Numpy計算導數?

Y = X 2 +1

比方說,我想在x = 5的衍生價值...

+3

您需要使用Sympy:http://sympy.org/en/index.html numpy的是一個數值計算Python的庫 – prrao 2012-03-26 16:55:33

+0

或者,您是否需要一種估算導數數值的方法?爲此,您可以使用有限差分方法,但請記住它們往往是非常嘈雜的。 – 2012-03-26 17:11:12

回答

88

您有四個選項

  1. 您可以使用Finite Differences
  2. 您可以使用Automatic Derivatives
  3. 您可以使用Symbolic Differentiation
  4. 您可以通過計算衍生品手。

有限差分無需外部工具,但容易出現數值誤差,如果你在一個多元的情況是,可能需要一段時間。

如果問題很簡單,符號區分是最理想的。現在符號方法變得相當強大。 SymPy是一個很好的與NumPy集成的項目。看看autowrap或lambdify函數或檢查出Jensen's blogpost about a similar question

自動衍生產品非常酷,不容易出現數字錯誤,但確實需要一些額外的庫(谷歌爲此,有幾個很好的選擇)。這是最強大,但也是最複雜/難以設置的選擇。如果你很好地將自己限制爲numpy語法,那麼Theano可能是一個不錯的選擇。

下面是使用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.] 
+0

對不起,如果這看起來很蠢,3之間有什麼區別。符號分化和4.手分化? – DrStrangeLove 2012-04-12 16:55:03

+8

當我說「象徵性區分」時,我打算暗示該過程是由計算機處理的。原則3和4的區別僅在於工作人員,計算機或程序員。由於一致性,可擴展性和懶惰,3優於4。如果3找不到解決方案,則4是必要的。 – MRocklin 2012-04-13 16:51:04

+1

非常感謝!但最後一行是[2. 2. 2. 2. 2.]? – DrStrangeLove 2012-04-14 02:18:36

22

NumPy的不提供一般的功能來計算的衍生物。但它可以處理多項式的簡單的特例:

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

如果要計算導數值,您可以使用中央差商對於絕大多數的應用脫身。在單個點處的導數,該公式將是類似

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

,如果你有橫座標的陣列x與相應的數組函數值的y,可以COMPUT衍生物的近似值與

numpy.diff(y)/numpy.diff(x) 
+2

'計算更一般情況下的數值導數很容易' - 我要求不同,計算一般情況下的數值導數是相當困難的。你只是選擇了很好的表現功能。 – 2012-03-26 17:18:37

+0

>>> print p ??之後的意思是什麼? (在第二行) – DrStrangeLove 2012-03-26 17:23:33

+0

@DrStrangeLove:這是指數。它意在模擬數學符號。 – 2012-03-26 17:26:31

2

取決於精度您可以根據需要解決它自己,用差異化的簡單證明級別:

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

我們實際上不能採用漸變的限制,但它的樂趣。 你得小心,但因爲

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

我能想到的最直接的方法是使用numpy's gradient function一個例子:

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

這樣,dydx將使用中央差來計算,並會與y的長度相同,不像numpy.diff,它使用前向差異並返回(n-1)大小的向量。

+0

如果dx不恆定會怎樣? – weberc2 2015-07-01 21:22:12

+2

@ weberc2,在這種情況下,您應該將一個向量除以另一個向量,但是需要手動分別用向前和向後導數來處理邊。 – Sparkler 2015-07-02 22:06:26

+1

或者您可以用常數dx插值y,然後計算梯度。 – IceArdor 2016-11-16 03:43:47

3

我會扔另一種方法對樁...

scipy.interpolate的很多樣條插值能夠提供衍生物。因此,使用線性樣條(k=1),樣條的導數(使用derivative()方法)應該等同於前向差。我並不完全確定,但我相信使用三次樣條函數導數將類似於中心差導數,因爲它使用來自前後的值來構造三次樣條函數。

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

假設你想使用numpy,您可以用數字用Rigorous definition計算在任何一點的函數的導數:

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

您還可以使用Symmetric derivative獲得更好的結果:

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

使用你的例子,完整的代碼應該是這樣的:

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

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

現在,你可以數字x=5找到衍生物:

In [1]: d_fun(5) 
Out[1]: 9.999999999621423