Python 将三维numpy阵列高效转换为一维numpy阵列

Python 将三维numpy阵列高效转换为一维numpy阵列,python,arrays,numpy,Python,Arrays,Numpy,我有一个3D numpy数组,格式如下: >>>img.shape (4504932, 2, 2) >>> img array([[[15114, 15306], [15305, 15304]], [[15305, 15306], [15303, 15304]], [[15305, 15306], [15303, 15304]], ..., [[15305, 15302], [15305, 1

我有一个3D numpy数组,格式如下:

>>>img.shape
(4504932, 2, 2)

>>> img
array([[[15114, 15306],
    [15305, 15304]],

   [[15305, 15306],
    [15303, 15304]],

   [[15305, 15306],
    [15303, 15304]],

   ..., 

   [[15305, 15302],
    [15305, 15302]]], dtype=uint16)
我想将其转换为一维numpy数组,其中每个条目都是上述img numpy数组中每个2x2子矩阵的总和

我已经能够通过以下方式完成此任务:

img_new = np.array([i.sum() for i in img])
>>> img_new
array([61029, 61218, 61218, ..., 61214, 61214, 61214], dtype=uint64)
这正是我想要的。但这太慢了,大约需要10秒。有没有一种更快的方法可以用?我在上面添加了img.shape,所以您对这个numpy数组的大小有了概念

编辑-其他信息: 我的img阵列也可以是4x4、5x5、7x7形式的3D阵列。。等子矩阵。这由变量sub_rows和sub_cols指定

sum允许您指定一个或多个轴来进行求和,而不仅仅是对整个数组求和。这允许NumPy在C中循环数组,每求和只执行几条机器指令,而不必经过Python字节码求值循环并创建大量包装器对象以粘贴在列表中。

使用NumPy方法apply\u over\u axes通常更快,事实上就是这样。我刚刚在4000x2x2阵列上进行了测试:

img = np.random.rand(4000,2,2)
timeit(np.apply_along_axis(np.sum, img, [1,2]))
# 1000 loops, best of 3: 721 us per loop
timeit(np.array([i.sum() for i in img]))
# 100 loops, best of 3: 17.2 ms per loop
你可以用-

验证结果

运行时测试


太快了。谢谢我现在在我的问题中补充一条信息。您是否可以发表评论让我知道这是否仍然适用。@user3250673:img.sumaxis=1,2仍然有效。它不依赖于任何轴的大小。谢谢大家的帮助。刚刚意识到我有一个小问题。我的img数组是dtype=uint16,因此我不能直接使用img.sumaxis=1,2。将astype设置为int32`会是一个坏主意吗?@user3250673:没有什么能阻止您在数据类型uint16的数组上使用sum,但是如果您担心它溢出,sum有一个数据类型参数。这将设置使用的累加器和生成的数组的数据类型。但是,请注意,当数组的数据类型的大小小于默认的平台整数时,NumPy将自动将总和提升为默认的平台整数大小,因此您可能已经获得了uint32或uint64而不是uint16。比使用img.sumaxis=…,…?否:更快,也更慢。timeitimg.sumaxis=1,2 10000个回路,最佳值为3:51.8 us/回路
img = np.random.rand(4000,2,2)
timeit(np.apply_along_axis(np.sum, img, [1,2]))
# 1000 loops, best of 3: 721 us per loop
timeit(np.array([i.sum() for i in img]))
# 100 loops, best of 3: 17.2 ms per loop
img_new = np.einsum('ijk->i',img)
In [42]: np.array_equal(np.array([i.sum() for i in img]),np.einsum('ijk->i',img))
Out[42]: True
In [34]: img = np.random.randint(0,10000,(10000,2,2)).astype('uint16')

In [35]: %timeit np.array([i.sum() for i in img]) # Original approach
10 loops, best of 3: 92.4 ms per loop

In [36]: %timeit img.sum(axis=(1, 2)) # From other solution
1000 loops, best of 3: 297 µs per loop

In [37]: %timeit np.einsum('ijk->i',img)
10000 loops, best of 3: 102 µs per loop