【问题标题】:What is the fastest way to find the min and max value of a large multidimensional numpy array?找到大型多维 numpy 数组的最小值和最大值的最快方法是什么?
【发布时间】:2020-10-23 16:09:22
【问题描述】:

我有一个 numpy 数组,由 20,000 个 220x220 像素的 RGB 图像组成。因此,数组X_data 的形状为(20000, 220, 220, 3)

我正在寻找找到整个数据集的最小和最大像素值的最快方法。我很欣赏这种类型的任务需要时间,因为我正在搜索大约 30 亿个像素值,但我希望改进我已经找到的解决方案;分别是:

选项 1:展平数组

在结果数组上使用np.flatten,然后使用np.minnp.max

flat = X_data.flatten()
np.min(flat)
np.max(flat)

这个方法总共花了 13 分 11 秒(墙上时间)来找到最小值和最大值。

选项 2:列表理解

使用np.aminnp.amax 查找每个图像的最小值和最大值,将它们附加到一个列表中,然后找到该列表的最小值和最大值:

min_val = np.min([np.amin(X_data[i]) for i in np.arange(X_data.shape[0])])
max_val = np.max([np.amax(X_data[i]) for i in np.arange(X_data.shape[0])])

这个方法总共花了 8 分钟(墙上时间)。

有没有更快的方法来完成这个任务?

编辑:

我忘记在问题的原始表述中提到我希望它适用于尚未重新缩放的图像数据集,即包含不同大小图像的图像数据集。这意味着使用np.minnp.max 将不起作用,即使它比上述选项更快。

非常感谢!

【问题讨论】:

  • 你有一个像样的多核CPU吗?你运行什么操作系统?
  • 我正在使用现成的 MacBook Air 2020,运行 Catalina 和 1.6 GHz 双核 Intel Core i5。
  • 那么你的意思是你的开场白是不正确的...... “图像是 220x220 每个”
  • “未重新缩放的图像数据集,即包含不同大小图像的数据集”与它有什么关系?为什么不包括np.minnp.max
  • 我想可以通过同时计算最小值和最大值来查找 np.min/np.max 的来源并保存另一个因子 2。只需为自己编写一个 np.minmax 函数即可。

标签: python arrays numpy image-processing


【解决方案1】:

由于flatten,第一种方法速度较慢,它会生成数据副本。在您的情况下,数据很大,因此运行时的很大一部分将用于内存分配。

另一方面,np.min 默认情况下会检查所有轴,例如:

np.min([[1,2],[3,4]])
# out: 1

所以你可以这样做:

min_val, max_val = np.min(X_data), np.max(X_data)

应该更快。

【讨论】:

  • 感谢您的回复! np.min 确实更快,但问题是它只有在所有图像大小相同的情况下才有效。我正在寻找一种适用于包含不同图像大小的数组的通用解决方案,但我没有在我的问题中明确说明,因此我将对此进行编辑。
  • @celery_gemini 在这种情况下,只有第二个选项有效。请注意,numpy 操作仅在同构数据上效果最佳,而您提到的情况并非如此。
【解决方案2】:

如果最大速度很重要,那么添加一个可以同时获取最大值和最小值的库可能是值得的。这样的例程只需要遍历大数组一次而不是两次。由于在任何现代平台上获取这些值都是完全受内存限制的(计算量很小),因此将内存访问减半可能会使执行时间减半。基本上,您可以以一个价格获得两个值。

This answer 有一个链接到 Python 的 Fortran 实现,发现 Numpy 函数也太慢了。但这是一个已有 8 年历史的答案,Numpy 实现中的情况可能有所改善。

DIPlib 是一个图像处理库(我是作者),因为我已经安装了它,所以我很容易尝试它的功能来获取数组中的最大值和最小值。我使用的数组比 OP 中的小,我不想等那么久才能完成实验。代码如下:

import numpy as np
import diplib as dip
import time

X = np.random.randn(2000, 220, 220, 3)

t = time.time()
np.min(X), np.max(X)
print(time.time() - t)

t = time.time()
dip.MaximumAndMinimum(X)
print(time.time() - t)

三次运行的中位数(不更改 X 数组)第一部分为 0.361 秒,第二部分为 0.135 秒。

【讨论】:

    【解决方案3】:

    找到最大值(或最小值)需要对值进行排序。当两者都需要时,调用np.max() 然后调用np.min() 使其对值进行两次排序...

    我更喜欢简单地使用这个:

    the_min, the_max = np.percentile(my_data,[0,100])
    

    只对数据进行一次排序...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 2021-07-31
      • 1970-01-01
      相关资源
      最近更新 更多