n维数组的numpy二阶导数

时间:2015-07-03 12:04:17

标签: python numpy derivative hessian-matrix

我有一组模拟数据,我希望在n维中找到最低的斜率。数据的间距沿着每个维度是恒定的,但不是全部相同(为了简单起见,我可以改变它)。

我可以忍受一些数字不准确,尤其是边缘。我非常希望不生成样条并使用该衍生物;仅仅根据原始值就足够了。

可以使用numpy函数计算numpy.gradient()的一阶导数。

import numpy as np

data = np.random.rand(30,50,40,20)
first_derivative = np.gradient(data)
# second_derivative = ??? <--- there be kudos (:

这是关于拉普拉斯与粗麻布矩阵的评论;这不再是一个问题,而是为了帮助理解未来的读者。

我使用2D功能作为测试用例来确定最平坦的&#39;低于阈值的区域。以下图片显示了使用second_derivative_abs = np.abs(laplace(data))的最小值与以下最小值之间的结果差异:

second_derivative_abs = np.zeros(data.shape)
hess = hessian(data)
# based on the function description; would [-1] be more appropriate? 
for i in hess[0]: # calculate a norm
    for j in i[0]:
        second_derivative_abs += j*j

色标表示功能值,箭头表示一阶导数(渐变),红点表示最接近零的点,红线表示阈值。

数据的生成器函数为( 1-np.exp(-10*xi**2 - yi**2) )/100.0,其中xi,yi由np.meshgrid生成。

拉​​普拉斯:

laplace solution

的Hessian:

hessian solution

4 个答案:

答案 0 :(得分:16)

二阶导数由Hessian matrix给出。这是ND数组的Python实现,包括应用np.gradient两次并适当地存储输出,

import numpy as np

def hessian(x):
    """
    Calculate the hessian matrix with finite differences
    Parameters:
       - x : ndarray
    Returns:
       an array of shape (x.dim, x.ndim) + x.shape
       where the array[i, j, ...] corresponds to the second derivative x_ij
    """
    x_grad = np.gradient(x) 
    hessian = np.empty((x.ndim, x.ndim) + x.shape, dtype=x.dtype) 
    for k, grad_k in enumerate(x_grad):
        # iterate over dimensions
        # apply gradient again to every component of the first derivative.
        tmp_grad = np.gradient(grad_k) 
        for l, grad_kl in enumerate(tmp_grad):
            hessian[k, l, :, :] = grad_kl
    return hessian

x = np.random.randn(100, 100, 100)
hessian(x)

请注意,如果您只对二阶导数的大小感兴趣,可以使用Laplace operator实现的scipy.ndimage.filters.laplace,这是Hessian矩阵的跟踪(对角元素之和)。

采用Hessian矩阵的最小元素可用于估计任何空间方向上的最低斜率。

答案 1 :(得分:1)

你可以看到Hessian矩阵是一个渐变渐变,你在这里计算的第一个渐变的每个分量第二次应用渐变是维基百科link definig Hessian矩阵,你可以清楚地看到它是一个渐变渐变,这里是一个定义渐变的python实现,然后是粗麻布:

import numpy as np
#Gradient Function
def gradient_f(x, f):
  assert (x.shape[0] >= x.shape[1]), "the vector should be a column vector"
  x = x.astype(float)
  N = x.shape[0]
  gradient = []
  for i in range(N):
    eps = abs(x[i]) *  np.finfo(np.float32).eps 
    xx0 = 1. * x[i]
    f0 = f(x)
    x[i] = x[i] + eps
    f1 = f(x)
    gradient.append(np.asscalar(np.array([f1 - f0]))/eps)
    x[i] = xx0
  return np.array(gradient).reshape(x.shape)

#Hessian Matrix
def hessian (x, the_func):
  N = x.shape[0]
  hessian = np.zeros((N,N)) 
  gd_0 = gradient_f( x, the_func)
  eps = np.linalg.norm(gd_0) * np.finfo(np.float32).eps 
  for i in range(N):
    xx0 = 1.*x[i]
    x[i] = xx0 + eps
    gd_1 =  gradient_f(x, the_func)
    hessian[:,i] = ((gd_1 - gd_0)/eps).reshape(x.shape[0])
    x[i] =xx0
  return hessian

作为测试,(x ^ 2 + y ^ 2)的Hessian矩阵 2 * I_2 其中I_2是维数2的单位矩阵

答案 2 :(得分:0)

坡度,黑森州和拉普拉斯人是相关的,但有3种不同。
以2d开头:2个变量的函数(x,y),例如一系列丘陵的高度图,

  • 斜率(也称为梯度)是方向矢量,每个点x y上的方向和长度。
    可以通过笛卡尔坐标中的两个数字dx dy来给出, 或极坐标中的角度θ和长度sqrt( dx^2 + dy^2 )。 在整个山丘上,我们得到了 vector field

  • 黑森斯描述x y附近的曲率,例如抛物面或鞍形 有4个数字:dxx dxy dyx dyy

  • 拉普拉斯算子在每个点dxx + dyy上都是1个数字x y。 在一系列的山丘上,我们得到了 scalar field。 (具有Laplacian = 0的功能或丘陵 特别平滑。)

对于点h附近的微小步长xy,坡度是线性拟合,并且是Hessians二次拟合:

f(xy + h)  ~  f(xy)
        +  slope . h    -- dot product, linear in both slope and h
        +  h' H h / 2   -- quadratic in h

这里xyslopeh是2个数字的向量, H是4个数字dxx dxy dyx dyy的矩阵。

N-d相似:斜率是N个数字的方向向量, 在每个点上,Hessian都是N ^ 2数的矩阵,而Laplacians是1数的矩阵。

(您可能会在上找到更好的答案 math.stackexchange。)

答案 3 :(得分:0)

hessians = np.asarray(np.gradient(np.gradient(f(X, Y))))
hessians[1:]

为 3-d 函数 f 工作。