numpy的reduceat()在Python中是什么意思?

7 投票
3 回答
7495 浏览
提问于 2025-04-18 10:32

我刚开始学习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 个回答

2

我也曾经很难理解这个例子,我觉得这篇帖子里还有一些内容没有解释清楚,部分在评论中提到过,所以我来试着解释一下。

基本功能

根据文档的说明,

对于每个索引 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=1i+1=3,所以我们会得到一个切片 array[1:3],也就是元素 1, 2,它们的和是 3。接着我们从 i=3i+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=0i+1=4 开始,也就是取前 4 个元素并返回它们的和,0+1+2+3=6。然后它从 i=4i+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=0i+1=3 取索引(行!),也就是

[ 0.,   1.,   2.,   3.],
[ 4.,   5.,   6.,   7.],
[ 8.,   9.,  10.,  11.],

对它们求和并放入第一行(你可以检查一下)。然后它遇到一个跳跃,所以你只得到一行,也就是第四行。接着它给你 1:2 行的和,这只有第二行,所以你得到这一行。然后又有一个跳跃,从 i=2i+1=0,这又只是一个行,这次是第三行。最后,它给出所有行的和,因为你是从 0 到末尾。

我就不讲列(axis=1)了,因为过程完全一样。希望这对你有帮助。

12

上面的回答是对的,但没有解释 .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() 函数时实际发生了什么!我不是说上面的回答错了,只是提供了另一种解释,让你更好地理解这个函数!希望这对你有帮助!谢谢!

4

这有点像一种滚动应用,看看这个:

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])

撰写回答