使用整数的memoryview索引Cython memoryview

3

我使用Cython尝试做到这一点:

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

编译器报错:

指定的memoryview索引无效,类型为int[:]

我该如何使用某种整数数组对这个memoryview进行索引? 只能使用切片吗?在旧的NumPy数组缓冲区支持中,我可以轻松使用基于'array'的索引。(我只是适应了我的代码以使用memoryviews,看看它是否会提高性能,但实际上它却出现了问题...)

2个回答

4

@ead提出自行展开循环的建议很不错,但我倾向于在底层的Numpy数组上进行这种索引操作,您可以使用memoryview的base属性访问它们:

array = array.base[sortIndices]

或者,另外一种选择是:
array = np.asarray(array)[sortIndices]

这种方法的优点是编码快速,只需要对您的工作ndarray代码进行最小修改即可。它有一些小缺点:

  • 没有Cython加速,因为它基本上是一个Python对象调用 - 我希望这不要影响太多,因为Numpy索引通常非常快,假设sortIndices足够长以抵消Python对象调用。

  • 如果底层对象实际上不是Numpy数组,则第一个版本会出错(因此该函数在可以接受的类型方面受到了一些限制,而比起原始的memoryview接口来说)。您可以通过使用第二个版本来解决这个问题,它应该创建一个围绕memoryview内存的Numpy数组。


1

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

Cython的文档指出

内存视图使用Python切片语法类似于NumPy。

"类似"意味着对于整数、切片(:)、省略号(...)和None(相当于numpy.newaxis('None'))是相同的,但是整数数组或布尔数组不能像在numpy中一样用作索引。

负责生成对类型化内存视图进行访问的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(即:...或例如0:33),也不是None,也不能强制转换为Py_ssize_t,因此无法像Cython一样处理它。
我的第一个想法是,在Cython的类型化内存视图中添加这个功能不会太难。但是以一种一致的方式做到这一点可能并不容易:操作的结果必须是一个新的类型化内存视图(因为我们无法原地更改手头的数组-结果数组可能具有完全不同的维度)-但底层缓冲区应该是哪种类型?在numpy世界中更容易,其中一切都是numpy数组,但类型化内存视图的底层缓冲区可以是numpy数组、array.array、堆栈上的c数组等等。
你现在最好的选择可能是手动展开这个重新排序(这样你就可以显式地选择底层缓冲区的类型),并通过它替换破损的代码,或者回退到numpy功能以执行此操作,如@DavidWs的答案所示。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接