在Cython中获取numpy数组子集的最快方法

2 python arrays numpy cython scipy

我有一个Cython函数,该函数接受2d nd.array(numpy数组)整数,并返回一个1d numpy数组,其长度与输入2d数组的长度相同。

import numpy as np
cimport numpy as np

np.import_array()
cimport cython
def func(np.ndarray[np.float_t, dim=2] input_arr):
   cdef np.ndarray[np.float_t, ndim=1] new_arr = ...
   # do stuff
   return new_arr
Run Code Online (Sandbox Code Playgroud)

在程序的另一个循环中,我想调用func,但将其传递给从另一个2d数组动态创建的2d数组。现在我有:

my_2d_numpy_array = np.array([[0.5, 0.1], [0.1, 10]]) # assume this is defined
cdef int N = 10000
cdef int k
for j in xrange(N)
  # find some element k of interest
  # create a 2d array on fly containing just the k-th to func()
  func(np.array([my_2d_numpy_array[k]], dtype=float))  # KEY LINE
Run Code Online (Sandbox Code Playgroud)

这行得通,但是我认为np.array每次循环内的调用都会产生巨大的开销,因为它可以追溯到Python。由于func只读取数组而不修改数组,我如何才能将其作为指针传递给数组视图,而不用回到Python来创建新数组?我只想将k第一个行拉出来my_2d_numpy_array并传递给func()

更新:一个相关的问题:如果我nd.array在循环中使用一个内部函数,但不需要nd.arrayin 的全部功能func,我可以func改为使用静态C数组nd.array作为替代吗?这样可以节省成本吗?大概然后您不必将对象传递给funcnd.array是一个对象)

Ian*_*anH 5

您想使用Cython内存视图。它们旨在在同一Cython模块的一部分函数之间传递数组切片。您可能需要在Cython模块中内联该函数以获得全部性能优势,但这并不总是必要的。您可以看一下文档。我最近为另一个问题写了一个相当冗长的答案,该问题探讨了何时应该使用内存视图。如果您想更详细地研究切片为何能很好地与内存视图配合使用,请参阅此博客文章

如果不使用内存视图,则涉及NumPy数组的切片仍会涉及Python调用,并且不会在C语言中执行。

对于您的特定情况,这里有一些想法:如果要在Cython模块中的函数之间传递数组切片,则应该能够使用内存视图来传递切片。这种方法确实取决于编译时的优化,因此,如果需要在两个分别在不同时间编译的函数之间传递数组,则必须使用指针在函数之间传递数据。这将意味着要进行一些仔细的指针算术运算,但是它仍然可以正常工作。如果需要切片并使用NumPy函数,则可能最终不得不使用NumPy数组,但是尝试使用NumPy数组和查看相同数据的内存视图可能是值得的。这样,您将能够将切片作为内存视图进行传递,而仅在真正需要它们时才需要创建NumPy数组。

另外,我建议将函数func设为C函数,这样您在调用它时就不必承担调用Python函数的开销。您可以通过使用cdefor cpdef关键字来声明它。cdef如果不需要从模块外部调用它,请使用。使用cpdef,如果你想有一个C函数和相应的Python包装是Python的访问。