3

使用 Cython,我尝试这样做:

cpdef myFun(double[:] array):
    cdef int[:] sortIndices = np.argsort(array, kind='mergesort')
    array = array[sortIndices]

编译器抱怨:

指定的内存视图索引无效,键入 int[:]

如何使用某种整数数组索引此内存视图?只允许切片吗?我可以轻松地使用基于“数组”的索引和旧的 NumPy 数组缓冲区支持。(我只是调整了我的代码以使用 memoryviews 来查看它是否会提高性能,但它实际上会中断......)

4

2 回答 2

4

@ead 关于自己展开循环的建议是一个很好的建议,但是我很想对底层的 Numpy 数组进行这种类型的索引,您可以使用basememoryview 的属性访问它:

array = array.base[sortIndices]

或者

array = np.asarray(array)[sortIndices]

这样做的好处是可以快速编码,并且只需要对您的工作ndarray代码进行最少的修改。它有几个小缺点:

  • 没有 Cython 加速,因为它基本上是一个 Python 对象调用 - 我希望这无关紧要,因为 Numpy 索引通常非常快,并且假设它sortIndices足够长以否定 Python 对象调用。

  • 如果底层对象实际上不是 Numpy 数组,则第一个版本会中断(因此,与最初出现的 memoryview 接口相比,该函数在可以采用的类型方面受到更多限制。您可以通过使用第二个版本来解决这个问题,这应该创建一个包裹在 memoryview 内存周围的 Numpy 数组。

于 2018-12-18T18:41:30.890 回答
0

恐怕不可能像 numpy 可以使用 int-arrays 那样使用类型化的内存视图作为索引。

Cython 的文档指出

内存视图以与 NumPy 类似的方式使用 Python 切片语法。

“相似”意味着它对于整数、切片:...Nonenumpy.newaxis('None')

负责生成对类型化内存视图的访问的 Cython 代码是generate_buffer_slice_code,您所需要知道的都在 doc-string 中:

 """ 
 Slice a memoryviewslice. 
 indices     - list of index nodes. 
 If not a SliceNode, or NoneNode,  then it must be coercible to Py_ssize_t 
 ....
 """

因此array,既不是 SliceNode(即:...或 eg 0:33),也不None能被强制转换Py_ssize_t为 Cython,因此不能按原样处理。

我的第一个想法是,将功能添加到 Cython 的类型化内存视图不会太难。但这可能不是那么容易以一致的方式完成:操作的结果必须是一个新的类型化内存视图(因为我们无法就地更改手头的数组 - 生成的数组可能具有完全不同的维度) - 但是哪种类型应该是底层缓冲区?在 numpy-world 中更容易,其中所有内容都是 numpy 数组,但类型化内存视图的底层缓冲区可能是 numpy-array、an array.array、堆栈上的 c-array 等等。

您现在最好的选择可能是手动推出这种重新排序(因此您可以明确选择底层缓冲区的类型)并通过它替换损坏的代码,或者回退到此操作的 numpy 功能,如@DavidWs answer所示.

于 2018-12-18T13:57:20.013 回答