numpy的reduceat()在Python中是什么意思?
我刚开始学习Python,现在正在看教程。
我对reduceat()
这个函数有点困惑。
我看到一个例子:
np.add.reduceat([0,1,2,3,4,5,6,7],[0,4,1,5,2,6,3,7])[::2]
结果是:
array([ 6, 10, 14, 18])
这个结果是怎么来的呢?有人能给我解释一下吗?
3 个回答
我也曾经很难理解这个例子,我觉得这篇帖子里还有一些内容没有解释清楚,部分在评论中提到过,所以我来试着解释一下。
基本功能
根据文档的说明,
对于每个索引 i 在范围(len(indices)) 中,reduceat 计算 ufunc.reduce(array[indices[i]:indices[i+1]])
这意味着 reduceat
会遍历给定列表中的所有索引,然后对数组进行切片,并在切片上执行给定的 ufunc
(在这里是对数字进行加法)。
升序索引
这一点被 @Adarsh_V_Desai 描述得很好,@CT Zhu 也展示了这个过程。根据答案和例子:
import numpy as np
array = np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
indices = np.array([1,3,4,5])
在循环的第一步,i=1
和 i+1=3
,所以我们会得到一个切片 array[1:3]
,也就是元素 1, 2
,它们的和是 3。接着我们从 i=3
到 i+1=4
,这时只有一个元素 3
。接下来也是一样,只有一个元素 4
。最后,我们从 i=5
开始到数组的末尾,因为没有其他索引(参考文档:
对于最后一个索引,indices[i+1] = array.shape[axis]),
这会得到 array[5:]
和元素 5, 6, 7, 8, 9
,它们的和是 35。
降序索引
问题来了,当我们有非升序或非降序的索引时会发生什么。原理是一样的,会回到问题中的原始例子。我们来看这个例子:
np.add.reduceat([0,1,2,3,4,5,6,7],[0,4,1,5,2,6,3,7])
如上所示,它从 i=0
到 i+1=4
开始,也就是取前 4 个元素并返回它们的和,0+1+2+3=6
。然后它从 i=4
到 i+1=1
,正如评论中提到的,如果尝试会得到 []
。但再次提醒,参考文档:
如果 indices[i] >= indices[i + 1],那么第 i 行的“行”就是 array[indices[i]]
这意味着我们只得到一个元素,也就是 4
。之后我们又像第一种情况一样继续,求和 4 个元素,然后再给出一行 = 一个元素 5
,等等。
为什么用 [::2]
从上面的例子中你可能已经看到了,我们得到线性上升,然后在需要从 4
跳回 1
时会有一个跳跃。我们得到单独的元素是因为索引列表中有降序的跳跃。而这正是 [::2]
所去掉的——它只取每隔一个的元素,由于我们在每个第二个位置都有跳跃,所以我们把它们从结果中去掉。
二维数组
你没有问,但我觉得提一下也有帮助(因为我一开始也对此感到困惑)。
x = np.linspace(0, 15, 16).reshape(4,4)
np.add.reduceat(x, [0, 3, 1, 2, 0])
array([[12., 15., 18., 21.],
[12., 13., 14., 15.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[24., 28., 32., 36.]])
这个复杂的东西做的事情和上面描述的完全一样。首先,它从 i=0
到 i+1=3
取索引(行!),也就是
[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
对它们求和并放入第一行(你可以检查一下)。然后它遇到一个跳跃,所以你只得到一行,也就是第四行。接着它给你 1:2
行的和,这只有第二行,所以你得到这一行。然后又有一个跳跃,从 i=2
到 i+1=0
,这又只是一个行,这次是第三行。最后,它给出所有行的和,因为你是从 0
到末尾。
我就不讲列(axis=1
)了,因为过程完全一样。希望这对你有帮助。
上面的回答是对的,但没有解释 .reduceat 实际上在做什么!简单来说,它是返回切片数组中元素的总和。
举个例子:
array = np.arange(10)
indices = np.array([1,3,4,5])
output = numpy.add.reduceat(array,indices)
print(output)
输出: [ 3 3 4 35]
在背后发生的事情是,它像下面这样对数组反复应用 .reduce():
print("Step1 : ", np.add.reduce(array[1:3]))
print("Step2 : ", np.add.reduce(array[3:4]))
print("Step3 : ", np.add.reduce(array[4:5]))
print("Step4 : ", np.add.reduce(array[5:]))
然后把每一步的结果添加到一个列表中,并显示最终结果!希望你能明白当你调用 numpy.add.reduceat() 函数时实际发生了什么!我不是说上面的回答错了,只是提供了另一种解释,让你更好地理解这个函数!希望这对你有帮助!谢谢!
这有点像一种滚动应用,看看这个:
In [59]:
np.add.reduceat([0,1,2,3,4,5,6,7],[0,4])
Out[59]:
array([ 6, 22])
In [65]:
np.add.reduceat([0,1,2,3,4,5,6,7],[4,1])
Out[65]:
array([ 4, 28])
In [66]:
np.add.reduceat([0,1,2,3,4,5,6,7],[1,5])
Out[66]:
array([10, 18])
In [64]:
np.add.reduceat([0,1,2,3,4,5,6,7],[5,2])
Out[64]:
array([ 5, 27])
In [61]:
np.add.reduceat([0,1,2,3,4,5,6,7],[2,6])
Out[61]:
array([14, 13])
In [67]:
np.add.reduceat([0,1,2,3,4,5,6,7],[6,3])
Out[67]:
array([ 6, 25])
In [62]:
np.add.reduceat([0,1,2,3,4,5,6,7],[3,7])
Out[62]:
array([18, 7])
如果你只想要第一个值,你可以一次性搞定:
In [63]:
np.add.reduceat([0,1,2,3,4,5,6,7],[0,4,1,5,2,6,3,7])
Out[63]:
array([ 6, 4, 10, 5, 14, 6, 18, 7])