web-dev-qa-db-fra.com

dérivée numpy seconde d'un tableau non dimensionnel

J'ai un ensemble de données de simulation où je voudrais trouver la pente la plus basse en n dimensions. L'espacement des données est constant le long de chaque dimension, mais pas toujours identique (je pourrais changer cela par souci de simplicité). 

Je peux vivre avec quelques imprécisions numériques, en particulier vers les bords. Je préférerais fortement ne pas générer de spline et utiliser ce dérivé; juste sur les valeurs brutes serait suffisant.

Il est possible de calculer la première dérivée avec numpy à l'aide de la fonction numpy.gradient()

import numpy as np

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

Ceci est un commentaire concernant laplace par rapport à la matrice de Hessian; Ce n'est plus une question, mais vise à aider à la compréhension des futurs lecteurs.

J'utilise comme test une fonction 2D pour déterminer la zone la plus «plate» sous un seuil. Les images suivantes montrent la différence de résultats entre l'utilisation du minimum de second_derivative_abs = np.abs(laplace(data)) et du minimum des éléments suivants:

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

L'échelle de couleur décrit les valeurs des fonctions, les flèches représentent la première dérivée (dégradé), le point rouge le point le plus proche de zéro et la ligne rouge le seuil.

La fonction de générateur pour les données était ( 1-np.exp(-10*xi**2 - yi**2) )/100.0 avec xi, yi étant généré avec np.meshgrid.

Laplace:

laplace solution

Toile de jute:

hessian solution

12
Faultier

Les dérivées secondes sont données par la matrice Hessian . Voici une implémentation Python pour les tableaux ND, qui consiste à appliquer deux fois le np.gradient et à stocker correctement la sortie,

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)

Notez que si vous êtes uniquement intéressé par la magnitude des dérivées secondes, vous pouvez utiliser l'opérateur Laplace implémenté par scipy.ndimage.filters.laplace , qui est la trace (somme d'éléments diagonaux) de la matrice de Hessian.

Prendre le plus petit élément de la matrice de Hesse pourrait être utilisé pour estimer la pente la plus basse dans n'importe quelle direction spatiale. 

16
rth

Vous pouvez voir la matrice de Hesse sous forme de dégradé, où vous appliquez un dégradé une seconde fois pour chaque composant du premier dégradé calculé ici. Il s'agit d'une matrice de Hesse wikipedia link / et vous pouvez voir clairement qu'il s'agit d'un dégradé. , voici une implémentation en python définissant le dégradé puis le hessien: 

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

Comme test, la matrice hessienne de (x ^ 2 + y ^ 2) est 2 * I_2 où I_2 est la matrice d'identité de la dimension 2

1
SENHAJI RHAZI Hamza