numpy.gradient是做什么用的?

76

我知道数学函数的梯度是什么,所以我觉得我应该知道 numpy.gradient 是什么。但是我不知道。documentation 也没有什么帮助:

返回一个 N 维数组的梯度。

一个数组的梯度是什么?numpy.gradient 何时有用?


3
文档中提供了更详细的描述:在内部使用中心差分,在边界使用第一差分来计算梯度。因此返回的梯度与输入数组具有相同的形状。请查看http://en.wikipedia.org/wiki/Finite_difference_method。 - Praveen
3
你可以将一维数组的离散导数定义为(x[i+1]-x[i])/h的形式(其中h通常为1),同样的方式,你也可以定义离散梯度;离散梯度在图像算法中经常被使用(详见http://en.wikipedia.org/wiki/Image_gradient)。 - Matteo Italia
4个回答

179

此外,在文档1中:

>>> y = np.array([1, 2, 4, 7, 11, 16], dtype=np.float)
>>> j = np.gradient(y)
>>> j 
array([ 1. ,  1.5,  2.5,  3.5,  4.5,  5. ])
  • 梯度定义为(y的变化量)/(x的变化量)。

  • 这里的x是列表索引,因此相邻值之间的差为1。

  • 在边界处,会计算第一个差分。这意味着在数组的每个端点,给出的梯度只是末尾两个值之间的差(除以1)。

  • 远离边界时,特定索引的梯度由取其左右两侧的值之差再除以2得出。

因此,以上是计算y的梯度的方法:

j[0] = (y[1]-y[0])/1 = (2-1)/1  = 1
j[1] = (y[2]-y[0])/2 = (4-1)/2  = 1.5
j[2] = (y[3]-y[1])/2 = (7-2)/2  = 2.5
j[3] = (y[4]-y[2])/2 = (11-4)/2 = 3.5
j[4] = (y[5]-y[3])/2 = (16-7)/2 = 4.5
j[5] = (y[5]-y[4])/1 = (16-11)/1 = 5

例如,您可以在结果数组中找到所有绝对值的最小值,以找到曲线的转折点。


1在文档示例中,该数组实际上被称为x,我将其更改为y以避免混淆。


6
太棒了!真的帮助我尝试在C++中编写这个函数。 - Patrick Cook
2
有人能解释一下为什么返回的数组与输入数组的大小相同,无论间距参数如何吗?我本来以为随着更大的间距它会变小。 - Alaa M.
3
在文档中,对于间距为2的示例,其值仅为未指定间距时结果的一半。因此看起来它意味着间距是虚拟x轴上每个点之间的距离,而不是默认值1。因此,数组的大小将保持不变。 - SiHa
@SiHa 这篇答案的结尾真应该加到numpy文档里。非常有帮助,谢谢。 - Decker
据我理解,np.gradient()可以用于返回信号的一阶导数 - 这是正确的吗?为了计算二阶导数,调用np.gradient()两次是否可行? 例如:derivative_2 = np.gradient(np.gradient(signal))? - epifanio
显示剩余2条评论

27

这里是正在发生的事情。泰勒级数展开指导我们如何近似求得导数,给定接近点的值。最简单的来自于C^2函数(两个连续导数)的一阶泰勒级数展开...

  • f(x+h)=f(x)+f'(x)h+f''(xi)h²/2。

可以解出f'(x)...

  • f'(x)=[f(x+h)-f(x)]/h+O(h)。

我们能做得更好吗?确实如此。如果我们假设C^3,则泰勒展开式为

  • f(x+h)=f(x)+f'(x)h+f''(x)h²/2+f'''(xi)h³/6,并且
  • f(x-h)=f(x)-f'(x)h+f''(x)h²/2-f'''(xi)h³/6。

将它们相减(h^0和h^2项都消失!)并解出f'(x):

  • f'(x)=[f(x+h)-f(x-h)]/(2h)+O(h²)。

因此,如果我们有一个在等距分区上定义的离散化函数:x=x_0,x_0+h(=x_1),....,x_n=x_0+h*n,然后numpy梯度会使用端点的一阶估计和中间更好的估计产生一个“导数”数组。

示例1。如果您没有指定任何间距,间隔被认为是1。所以如果你调用

f = np.array([5, 7, 4, 8])

你的意思是 f(0) = 5,f(1) = 7,f(2) = 4,以及 f(3) = 8。那么

np.gradient(f) 

将会是:f'(0) = (7 - 5)/1 = 2, f'(1) = (4 - 5)/(2*1) = -0.5, f'(2) = (8 - 7)/(2*1) = 0.5, f'(3) = (8 - 4)/1 = 4.

例子2。 如果您指定单个空格,间距是均匀的但不为1。

例如,如果您调用

np.gradient(f, 0.5)

这句话的意思是h=0.5而不是1,也就是说,函数实际上是f(0)=5,f(0.5)=7,f(1.0)=4,f(1.5)=8。总的影响是将h=1替换为h=0.5,所有结果都会增加一倍。

例子3. 假设离散化函数f(x)不是在均匀间隔上定义的,例如f(0)=5,f(1)=7,f(3)=4,f(3.5)=8,则有一个更混乱的离散化差分函数被numpy gradient函数使用,您可以通过调用函数得到离散的导数。

np.gradient(f, np.array([0,1,3,3.5]))

最后,如果你的输入是二维数组,则意味着你在考虑定义在网格上的函数 f(x, y)。Numpy 梯度会输出 x 和 y 方向上“离散化”的偏导数数组。


2
我创建了一个视频来解释这个问题... https://www.youtube.com/watch?v=NvP7iZhXqJQ - Robert McLean MD PhD

24
块引用: 梯度在内部使用中心差分计算,在边界处使用一阶差分计算。

块引用: 默认距离为1。
这意味着在内部计算时,它是按照有限差分的方式进行计算的。

enter image description here

其中 h = 1.0

并且在边界处

enter image description here


5
你确定 h=1 吗?因为这意味着它是 *f(x + 0.5) - f(x - 0.5)*,所以如果我们取 x = 2,它就变成了 *f(2.5) - f(1.5)*,如果 f 是一个一维数组,你不能有非整数的 x。看起来实际上应该是 *f(x + 1) - f(x - 1)*。 - Andrey
16
暗色主题下我无法看到你的公式。 - asrulsibaoel

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接