np.gradient() - 一个简单的图解指南

4,890 阅读6分钟

5/5 - (3票)

在Python中,numpy.gradient() 函数逼近一个N维数组的梯度。它在内部点使用二阶精确中心差分,在边界使用一阶或二阶精确单边差分进行梯度逼近。因此,返回的梯度具有与输入数组相同的形状。

下面是numpy.gradient() 的参数表。

参数接受参数描述
farray_like一个包含标量函数样本的N维输入阵列。
varargs标量或数组的列表,可选f 值之间的间距。所有维度的默认单元间距。
edge_order{1, 2},可选梯度在边界处使用N阶实数差计算。默认:1。
axisNone 或 或ints的元组,可选int梯度只沿给定的一个或多个轴计算。默认(axis = None)是计算输入数组中所有轴的梯度。axis可能是负数,在这种情况下,它从最后一个轴算到第一个轴。

如果你觉得听起来不错,请继续阅读,通过PythonNumPy的代码片段和生动的视觉效果,你将充分了解numpy.gradient() 函数。

  • 首先,我将介绍它的基本概念、numpy.gradient() 语法和参数。
  • 然后,你将学习这个函数的一些基本例子。
  • 最后,我将解决关于numpy.gradient() 的两个首要问题,包括np.gradient edge_ordernp.gradient axis

你可以在这里找到本教程的所有代码。

此外,我另一篇关于numpy.diff() 方法的精彩指南中解释了numpy.diff()numpy.gradient() 的区别。

基本的概念。梯度和有限差分

对于这一部分,如果你对梯度和有限差分很熟悉,可以跳过这一部分,去看它的语法和论据!

🎓度的定义。在矢量微积分中,几个变量的标量值可微调函数f的梯度是一个矢量场,其在某一点p的值是矢量,其组成部分是fp的偏导数

例如,下图中的蓝色箭头描述了函数f(x,y)=-(cos2x + cos2y)^2的梯度,作为底层平面上的一个投影向量场。

直观地说,你可以把梯度看作是一个点上最快增加或减少方向的指标。在计算上,梯度是一个包含某点所有偏导数的向量。

由于numpy.gradient() 函数使用有限差分来近似梯度,我们还需要了解一些有限差分的基本知识。

🎓 有限差分的定义。有限差分是一个数学表达式,其形式为f(x+b)-f(x+a)。如果有限差分除以b-a,就得到一个差分商。(维基百科)

不要惊慌!这里有我手写的一阶和二阶正向、反向和中心差分的解释和推导。这些公式是由numpy.gradient 在引擎盖下使用的。

语法和论据

这里是numpy.gradient()语法

# Syntax
numpy.gradient(f[, *varargs[, axis=None[, edge_order=1]]])

这里是numpy.gradient()参数表

稍后,我将更深入地讨论参数,edge_orderaxis

至于参数varargs ,你现在可以不使用它,当你有非单数间隔尺寸时再使用它。🙂

numpy.gradient() 函数的输出是一个ndarrays (如果只有一个维度,则是一个ndarray )的列表,对应于输入f 相对于每个维度的导数。每个导数的形状与输入f 相同。

基本例子

从图片上看,这里是一个一维数组中梯度计算的说明。

下面是一个一维数组的代码例子。

import numpy as np

one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
gradient = np.gradient(one_dim)
print(gradient)
'''
# * Underlying Gradient Calculation:
# Default edge_order = 1
gradient[0] = (one_dim[1] - one_dim[0])/1 = (2. - 1.)/1 = 1. 

# Interior points
gradient[1] = (one_dim[2] - one_dim[0])/2 = (4. - 1.)/2 = 1.5
gradient[2] = (one_dim[3] - one_dim[1])/2 = (8. - 2.)/2 = 3.
gradient[3] = (one_dim[4] - one_dim[2])/2 = (16. - 4.)/2 = 6.

# Default edge_order = 1
gradient[4] = (one_dim[4] - one_dim[3])/1 = (16. - 8.)/1 = 8. 
'''

输出。

np.gradient() edge_order

在我们的基本例子中,我们没有向numpy.gradient() 函数传递任何参数。

在本节中,我将向你展示如何部署参数edge_order ,并为边界元素设置不同的顺序差。

只是为了唤起你的记忆,这里是numpy.gradient() 的参数表。

我们可以将参数edge_order 设为1或2。它的默认值是1。

首先,我们之前的基本例子使用它的默认值1。

import numpy as np

# edge_order = 1
one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
gradient = np.gradient(one_dim, edge_order=1)
print(gradient)
'''
# * Underlying Gradient Calculation:
# Default edge_order = 1
gradient[0] = (one_dim[1] - one_dim[0])/1 = (2. - 1.)/1 = 1. 

# Interior points
gradient[1] = (one_dim[2] - one_dim[0])/2 = (4. - 1.)/2 = 1.5
gradient[2] = (one_dim[3] - one_dim[1])/2 = (8. - 2.)/2 = 3.
gradient[3] = (one_dim[4] - one_dim[2])/2 = (16. - 4.)/2 = 6.

# Default edge_order = 1
gradient[4] = (one_dim[4] - one_dim[3])/1 = (16. - 8.)/1 = 8. 
'''

输出。

其次,我们可以将edge_order 设为2,计算边界元素的二阶差分。

import numpy as np
# edge_order = 2
one_dim = np.array([1, 2, 4, 8, 16], dtype=float)
gradient = np.gradient(one_dim, edge_order=2)
print(f'edge_order = 2 -> {gradient}')
'''
# * Underlying Gradient Calculation:
# edge_order = 2
gradient[0] = (4*one_dim[0+1] - one_dim[0+2*1] - 3*one_dim[0])/(2*1) 
            = (4*2. - 4. + 3*1.)/2 = 0.5 

# Interior points
gradient[1] = (one_dim[2] - one_dim[0])/2 = (4. - 1.)/2 = 1.5
gradient[2] = (one_dim[3] - one_dim[1])/2 = (8. - 2.)/2 = 3.
gradient[3] = (one_dim[4] - one_dim[2])/2 = (16. - 4.)/2 = 6.

# edge_order = 2
gradient[4] = (3*one_dim[4] + one_dim[4-2*1] - 4*one_dim[4-1])/(2*1) 
            = (3*16. + 4. - 4*8.)/2 
            = 10. 
'''

输出。

关于二阶正向和反向差分公式的原理,请看我之前手写的推导。我知道它们看起来确实很奇怪,但是背后有一个逻辑🙂

np.gradient()轴

在这一部分,我将告诉你如何部署参数axis ,并通过一个2D数组的例子计算(实际上是近似)你想要的维度的梯度。

为了加深你的记忆,这里是numpy.gradient() 的参数表。

当我们有一个不止一个维度的输入时,我们可以将axis 参数设置为Noneint整数,以近似计算相应轴的梯度。

让我们以一个二维数组为例。

首先,让我们看看默认值,None ,会有什么作用。

import numpy as np

# axis = None (Default)
two_dim = np.array([[1, 2, 4, 8, 16],
                    [2, 5, 8, 10, 20]], dtype=float)
gradient = np.gradient(two_dim, axis=None)
# Same as:
# gradient = np.gradient(two_dim)
print(f'axis = None (Default): \n\n{gradient}')
print('\n', type(gradient))

输出。

我们可以看到,如果axis = Nonenumpy.gradient() 函数将输出输入数组的所有轴的梯度。

在这种情况下,我们也可以向axis 参数传递一个整数。

import numpy as np

# axis = int
two_dim = np.array([[1, 2, 4, 8, 16],
                    [2, 5, 8, 10, 20]], dtype=float)
row_gradient = np.gradient(two_dim, axis=0)
col_gradient = np.gradient(two_dim, axis=1)

# Same as:
# row_gradient = np.gradient(two_dim, axis=-2)
# col_gradient = np.gradient(two_dim, axis=-1)

print(f'axis = 0 or -2: \n\n{row_gradient}')
print('-'*85)
print(f'axis = 1 or -1: \n\n{col_gradient}')

输出。

最后,我们可以尝试向axis 参数传递一个整数。

import numpy as np

# axis = a tuple of ints
two_dim = np.array([[1, 2, 4, 8, 16],
                    [2, 5, 8, 10, 20]], dtype=float)
gradient = np.gradient(two_dim, axis=[0, 1])

print(f'axis = [0,1]: \n\n{gradient}')

输出。

总结

我们的文章np.gradient() ,到此为止。

我们了解了它的基本概念、语法、参数和基本例子。

我们还研究了关于np.gradient() 函数的前两个问题,包括np.gradient edge_ordernp.gradient axis

希望你喜欢这一切,并祝你编码愉快!