有时您必须对一个或多个大型 Numpy
阵列执行许多中间操作。这会很快导致 MemoryError
s。到目前为止,在我的研究中,我发现 Pickling(Pickle、CPickle、Pytables 等)和 gc.collect()
是缓解这种情况的方法。我想知道在处理大量数据时是否还有经验丰富的程序员使用的任何其他技术(当然除了删除策略/代码中的冗余之外)。
此外,如果有一件事我可以肯定,那就是没有什么是免费的。对于其中一些技术,有哪些权衡取舍(即速度、稳健性等)?
原文由 Noob Saibot 发布,翻译遵循 CC BY-SA 4.0 许可协议
我感觉到你的痛苦……你有时最终会存储数倍于数组大小的值,这些值稍后会被丢弃。当一次处理数组中的一项时,这是无关紧要的,但在矢量化时可能会杀死你。
我将使用工作中的示例进行说明。我最近使用 numpy 对 这里 描述的算法进行了编码。它是一种颜色映射算法,它获取 RGB 图像并将其转换为 CMYK 图像。对每个像素重复该过程,如下所示:
你可以做几件事来处理这个问题:
1. 分而治之
也许您无法一次性处理 1,000x1,000 的数组。但是,如果您可以使用 python for 循环迭代 10 个 100x1,000 的数组,它仍然会远远超过超过 1,000,000 个项目的 python 迭代器!它会变慢,是的,但不会那么慢。
2.缓存昂贵的计算
这与我上面的插值示例直接相关,并且更难遇到,尽管值得关注它。因为我是在每个维度有 4 位的三维立方体上进行插值,所以只有 16x16x16 种可能的结果,可以存储在 16 个 16x16x16 字节的数组中。所以我可以预先计算它们并使用 64KB 的内存存储它们,并为整个图像一个一个地查找值,而不是以巨大的内存成本为每个像素重做相同的操作。这已经为小至 64x64 像素的图像带来了回报,并且基本上允许处理像素数量为 x6 倍的图像,而无需细分阵列。
3. 明智地使用你的
dtypes
如果您的中间值可以放在单个
uint8
中,请不要使用int32
的数组!由于静默溢出,这可能会变成神秘错误的噩梦,但如果你小心的话,它可以节省大量资源。