scipy.differentiate.

jacobian#

scipy.differentiate.jacobian(f, x, *, tolerances=None, maxiter=10, order=8, initial_step=0.5, step_factor=2.0, step_direction=0)[原始碼]#

數值評估函數的 Jacobian 矩陣。

參數:
fcallable

想要計算 Jacobian 矩陣的函數。簽名必須是

f(xi: ndarray) -> ndarray

其中 xi 的每個元素都是有限實數。如果要微分的函數接受額外參數,請將其包裝(例如使用 functools.partiallambda),並將包裝後的 callable 傳遞給 jacobianf 不得改變陣列 xi。請參閱關於向量化以及輸入和輸出維度的註解。

xfloat array_like

評估 Jacobian 矩陣的點。必須至少有一個維度。請參閱關於維度和向量化的註解。

tolerancesdictionary of floats, optional

絕對和相對容差。字典的有效鍵為

  • atol - 導數的絕對容差

  • rtol - 導數的相對容差

res.error < atol + rtol * abs(res.df) 時,迭代將停止。預設的 atol 是適當 dtype 的最小正規數,而預設的 rtol 是適當 dtype 精度的平方根。

maxiterint, default: 10

要執行的演算法最大迭代次數。請參閱註解。

orderint, default: 8

要使用的有限差分公式的(正整數)階數。奇數將四捨五入到下一個偶數。

initial_stepfloat array_like, default: 0.5

有限差分導數近似的(絕對)初始步長。必須可與 xstep_direction 廣播。

step_factorfloat, default: 2.0

每次迭代中步長減小的因子;即,迭代 1 中的步長為 initial_step/step_factor。如果 step_factor < 1,則後續步驟將大於初始步驟;如果小於某個閾值的步驟是不希望的(例如,由於減法消去誤差),這可能很有用。

step_directioninteger array_like

表示有限差分步長方向的陣列(例如,當 x 接近函數域的邊界時使用。)必須可與 xinitial_step 廣播。其中 0(預設值),使用中心差分;其中為負數(例如 -1),步長為非正數;其中為正數(例如 1),所有步長為非負數。

返回:
res_RichResult

類似於 scipy.optimize.OptimizeResult 實例的物件,具有以下屬性。描述的寫法就好像這些值將是純量;但是,如果 f 返回一個陣列,則輸出將是相同形狀的陣列。

successbool array

演算法成功終止的地方為 True (狀態 0 );否則為 False

statusint array

表示演算法退出狀態的整數。

  • 0 : 演算法收斂到指定的容差。

  • -1 : 錯誤估計值增加,因此迭代終止。

  • -2 : 已達到最大迭代次數。

  • -3 : 遇到非有限值。

dffloat array

如果演算法成功終止,則為 fx 處的 Jacobian 矩陣。

errorfloat array

錯誤估計值:Jacobian 矩陣的當前估計值與前一次迭代中的估計值之間的差異量級。

nitint array

執行的演算法迭代次數。

nfevint array

評估 f 的點數。

屬性的每個元素都與 df 的對應元素相關聯。例如, nfev 的元素 i 是為了計算 df 的元素 i 而評估 f 的點數。

另請參閱

derivative, hessian

註解

假設我們希望評估函數 \(f: \mathbf{R}^m \rightarrow \mathbf{R}^n\) 的 Jacobian 矩陣。將正整數值 \(m\)\(n\) 分別賦給變數 mn,並讓 ... 表示整數的任意元組。如果我們希望在單個點評估 Jacobian 矩陣,則

  • 引數 x 必須是形狀為 (m,) 的陣列

  • 引數 f 必須向量化以接受形狀為 (m, ...) 的陣列。第一個軸表示 \(f\)\(m\) 個輸入;其餘部分用於在單次呼叫中評估多個點的函數。

  • 引數 f 必須返回形狀為 (n, ...) 的陣列。第一個軸表示 \(f\)\(n\) 個輸出;其餘部分用於評估多個點的函數結果。

  • 結果物件的屬性 df 將是形狀為 (n, m) 的陣列,即 Jacobian 矩陣。

此函數也以 Jacobian 矩陣可以在單次呼叫中評估 k 個點的意義上進行向量化。在這種情況下, x 將是形狀為 (m, k) 的陣列, f 將接受形狀為 (m, k, ...) 的陣列並返回形狀為 (n, k, ...) 的陣列,並且結果的 df 屬性將具有形狀 (n, m, k)

假設所需的 callable f_not_vectorized 未向量化;它只能接受形狀為 (m,) 的陣列。滿足所需介面的簡單解決方案是將 f_not_vectorized 包裝如下

def f(x):
    return np.apply_along_axis(f_not_vectorized, axis=0, arr=x)

或者,假設所需的 callable f_vec_q 已向量化,但僅適用於形狀為 (m, q) 的 2D 陣列。為了滿足所需的介面,請考慮

def f(x):
    m, batch = x.shape[0], x.shape[1:]  # x.shape is (m, ...)
    x = np.reshape(x, (m, -1))  # `-1` is short for q = prod(batch)
    res = f_vec_q(x)  # pass shape (m, q) to function
    n = res.shape[0]
    return np.reshape(res, (n,) + batch)  # return shape (n, ...)

然後將包裝後的 callable f 作為 jacobian 的第一個引數傳遞。

參考文獻

[1]

Jacobian 矩陣和行列式, 維基百科, https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant

範例

Rosenbrock 函數從 \(\mathbf{R}^m \rightarrow \mathbf{R}\) 映射;SciPy 實作 scipy.optimize.rosen 已向量化以接受形狀為 (m, p) 的陣列並返回形狀為 p 的陣列。假設我們希望在 [0.5, 0.5, 0.5] 處評估 Jacobian 矩陣(又稱梯度,因為函數返回純量)。

>>> import numpy as np
>>> from scipy.differentiate import jacobian
>>> from scipy.optimize import rosen, rosen_der
>>> m = 3
>>> x = np.full(m, 0.5)
>>> res = jacobian(rosen, x)
>>> ref = rosen_der(x)  # reference value of the gradient
>>> res.df, ref
(array([-51.,  -1.,  50.]), array([-51.,  -1.,  50.]))

作為具有多個輸出的函數範例,請考慮 [1] 中的範例 4。

>>> def f(x):
...     x1, x2, x3 = x
...     return [x1, 5*x3, 4*x2**2 - 2*x3, x3*np.sin(x1)]

真實的 Jacobian 矩陣由下式給出

>>> def df(x):
...         x1, x2, x3 = x
...         one = np.ones_like(x1)
...         return [[one, 0*one, 0*one],
...                 [0*one, 0*one, 5*one],
...                 [0*one, 8*x2, -2*one],
...                 [x3*np.cos(x1), 0*one, np.sin(x1)]]

在任意點評估 Jacobian 矩陣。

>>> rng = np.random.default_rng()
>>> x = rng.random(size=3)
>>> res = jacobian(f, x)
>>> ref = df(x)
>>> res.df.shape == (4, 3)
True
>>> np.allclose(res.df, ref)
True

在單次呼叫中評估 10 個任意點的 Jacobian 矩陣。

>>> x = rng.random(size=(3, 10))
>>> res = jacobian(f, x)
>>> ref = df(x)
>>> res.df.shape == (4, 3, 10)
True
>>> np.allclose(res.df, ref)
True