在Python中计算雅可比矩阵

时间:2018-03-29 09:53:44

标签: python numpy derivative

import numpy as np


a = np.array([[1,2,3],
              [4,5,6],
              [7,8,9]])


b = np.array([[1,2,3]]).T

c = a.dot(b) #function

jacobian = a # as partial derivative of c w.r.t to b is a.

我正在阅读jacobian Matrix,尝试构建一个,从我到目前为止所读到的,这个python代码应该被视为jacobian。我明白了吗?

6 个答案:

答案 0 :(得分:4)

Jacobian仅针对向量值函数进行定义。你不能使用填充常量的数组来计算雅可比矩阵;你必须知道基础函数及其偏导数,或者这些函数的数值近似。当您考虑常量(相对于某事物)的(部分)导数为0时,这是显而易见的。

在Python中,您可以使用符号数学模块,例如SymPySymEngine来计算函数的雅可比行列式。这是维基百科示例的简单演示:

  

enter image description here

使用SymEngine模块:

Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import symengine
>>>
>>>
>>> vars = symengine.symbols('x y') # Define x and y variables
>>> f = symengine.sympify(['y*x**2', '5*x + sin(y)']) # Define function
>>> J = symengine.zeros(len(f),len(vars)) # Initialise Jacobian matrix
>>>
>>> # Fill Jacobian matrix with entries
... for i, fi in enumerate(f):
...     for j, s in enumerate(vars):
...         J[i,j] = symengine.diff(fi, s)
...
>>> print J
[2*x*y, x**2]
[5, cos(y)]
>>>
>>> print symengine.Matrix.det(J)
2*x*y*cos(y) - 5*x**2

答案 1 :(得分:4)

您可以使用哈佛autograd库(link),其中gradjacobian以函数作为参数:

import autograd.numpy as np
from autograd import grad, jacobian

x = np.array([5,3], dtype=float)

def cost(x):
    return x[0]**2 / x[1] - np.log(x[1])

gradient_cost = grad(cost)
jacobian_cost = jacobian(cost)

gradient_cost(x)
jacobian_cost(np.array([x,x,x]))

否则,您可以使用jacobian中适用于矩阵的sympy方法:

from sympy import sin, cos, Matrix
from sympy.abc import rho, phi

X = Matrix([rho*cos(phi), rho*sin(phi), rho**2])
Y = Matrix([rho, phi])

X.jacobian(Y)

此外,您可能还希望看到此低级变体(link)。

答案 2 :(得分:2)

在python 3中,您可以尝试sympy包:

import sympy as sym

def Jacobian(v_str, f_list):
    vars = sym.symbols(v_str)
    f = sym.sympify(f_list)
    J = sym.zeros(len(f),len(vars))
    for i, fi in enumerate(f):
        for j, s in enumerate(vars):
            J[i,j] = sym.diff(fi, s)
    return J

Jacobian('u1 u2', ['2*u1 + 3*u2','2*u1 - 3*u2'])

给出:

Matrix([[2,  3],[2, -3]])

答案 3 :(得分:2)

尽管autograd是一个很好的库,但请务必检查其upgraded version JAX,该文件已被很好地记录下来(与autograd相比)。

一个简单的例子:

import jax.numpy as jnp
from jax import jacfwd

# Define some simple function.
def sigmoid(x):
    return 0.5 * (jnp.tanh(x / 2) + 1)
# Note that here, I want a derivative of a "vector" output function (inputs*a + b is a vector) wrt a input 
# "vector" a at a0: Derivative of vector wrt another vector is a matrix: The Jacobian
def simpleJ(a, b, inputs): #inputs is a matrix, a & b are vectors
    return sigmoid(jnp.dot(inputs, a) + b)

inputs = jnp.array([[0.52, 1.12,  0.77],
                   [0.88, -1.08, 0.15],
                   [0.52, 0.06, -1.30],
                   [0.74, -2.49, 1.39]])

b = jnp.array([0.2, 0.1, 0.3, 0.2])
a0 = jnp.array([0.1,0.7,0.7])

# Isolate the function: variables to be differentiated from the constant parameters
f = lambda a: simpleJ(a, b, inputs) # Now f is just a function of variable to be differentiated

J = jacfwd(f)
# Till now I have only calculated the derivative, it still needs to be evaluated at a0.
J(a0)

答案 4 :(得分:1)

这是向量函数f(x)的数学Jacobian的python实现,假定该函数返回一维numpy数组。

import numpy as np

def J(f,x,dx):
    n=len(x)
    func=f(x)
    jac=np.zeros((n,n))
    for j in range(n): #through columns
        Dxj=(abs(x[j])*dx if x[j]!=0 else dx)
        x_plus=[(xi if k!=j else xi+Dxj) for k,xi in enumerate(x)]
        jac[:,j]=(f(x_plus)-func)/Dxj
    return jac

建议制作dx〜10 ^ -8。

答案 5 :(得分:0)

如果您想一次通过数值找到许多点的雅可比行列式(例如,如果您的函数接受形状(n,x)并输出(n,y)),则为一个函数。从本质上讲,这是詹姆斯·卡特的答案,但有很多要点。 dx可能需要根据他的答案中的绝对值进行调整。

def numerical_jacobian(f, xs, dx=1e-6):
  """
      f is a function that accepts input of shape (n_points, input_dim)
      and outputs (n_points, output_dim)

      return the jacobian as (n_points, output_dim, input_dim)
  """
  if len(xs.shape) == 1:
    xs = xs[np.newaxis, :]
    
  assert len(xs.shape) == 2

  ys = f(xs)
  
  x_dim = xs.shape[1]
  y_dim = ys.shape[1]
  
  jac = np.empty((xs.shape[0], y_dim, x_dim))
  
  for i in range(x_dim):
    x_try = xs + dx * e(x_dim, i + 1)
    jac[:, :, i] = (f(x_try) - ys) / dx
  
  return jac

def e(n, i):
  ret = np.zeros(n)
  ret[i - 1] = 1.0
  return ret