提高高度重复的numpy数组索引操作的性能

时间:2017-09-07 14:48:35

标签: python arrays performance numpy memoryview

在我的程序代码中,我有numpy个值数组和numpy索引数组。在程序初始化期间,这两种都是预先分配和预定义的 程序的每个部分都有一个数组values,在其上执行计算,以及三个索引数组idx_from_exchidx_valuesidx_to_exch。有一个全局值数组来交换几个部分的值:exch_arr
索引数组大多数时间都有2到5个索引,很少(很可能永远不会)需要更多的索引。 dtype=np.int32shape和值在整个程序运行期间保持不变。因此我在初始化后设置ndarray.flags.writeable=False,但这是可选的。索引数组idx_valuesidx_to_exch的索引值按数字顺序排序,idx_source 可以排序,但无法定义。对应于一个值数组/部分的所有索引数组具有相同的shape values数组以及exch_arr通常包含50到1000个元素。 shapedtype=np.float64在整个程序运行期间保持不变,数组的值在每次迭代中都会发生变化。该
以下是示例数组:

import numpy as np
import numba as nb

values = np.random.rand(100) * 100  # just some random numbers
exch_arr = np.random.rand(60) * 3  # just some random numbers
idx_values = np.array((0, 4, 55, -1), dtype=np.int32)  # sorted but varying steps
idx_to_exch = np.array((7, 8, 9, 10), dtype=np.int32)  # sorted and constant steps!
idx_from_exch = np.array((19, 4, 7, 43), dtype=np.int32)  # not sorted and varying steps

示例索引操作如下所示:

values[idx_values] = exch_arr[idx_from_exch]  # get values from exchange array
values *= 1.1  # some inplace array operations, this is just a dummy for more complex things
exch_arr[idx_to_exch] = values[idx_values]  # pass some values back to exchange array

由于这些操作每次迭代应用一次,持续数百万次迭代,因此速度至关重要。我一直在研究增加索引速度in my previous question的许多不同方法,但是考虑到我的应用程序(特别是通过使用常量索引数组索引并将它们传递给另一个索引数组来获取值),我忘了具体到这一点。
到目前为止,最好的方法似乎是花哨的索引。我目前也正在尝试使用numba guvectorize,但似乎不值得努力,因为我的数组非常小。 memoryviews会很好,但由于索引数组不一定有一致的步骤,我知道无法使用memoryviews

那么有没有更快的方法来重复索引?为每个索引操作预定义内存地址数组的一些方法,dtypeshape总是不变的? ndarray.__array_interface__给了我一个内存地址,但我无法用它来编制索引。我想到了类似的东西:

stride_exch = exch_arr.strides[0]
mem_address = exch_arr.__array_interface__['data'][0]
idx_to_exch = idx_to_exch * stride_exch + mem_address

这可行吗? 我也一直在考虑直接使用stridesas_strided,但据我所知,只允许一致的步幅,我的问题需要不一致strides

任何帮助表示赞赏! 提前谢谢!

修改
我刚刚在示例计算中纠正了一个大错误! 操作values = values * 1.1 更改了数组的内存地址。我在程序代码中的所有操作都被布置为不更改数组的内存地址,因为很多其他操作都依赖于使用内存视图。因此,我用正确的就地操作替换了虚拟操作:values *= 1.1

0 个答案:

没有答案