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

时间:2014-02-24 05:24:07

标签: python arrays numpy scipy cython

我有一个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

在程序的另一个循环中,我想调用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

这有效,但我认为每次在循环内调用np.array会产生巨大的开销,因为它会回到Python。由于func只读取数组而不修改它,我怎样才能将数组视图作为指针传递给它,而不是通过回到Python来创建一个新数组?我只想提取k my_2d_numpy_arrayfunc()并将其传递给nd.array

更新:一个相关问题:如果我在循环中使用nd.array但在func中不需要func的完整功能,我可以让nd.array取而代之的是静态C数组,并以某种方式对待func吗?这会节省成本吗?大概那么你不必将对象传递给nd.array({{1}}是一个对象)

2 个答案:

答案 0 :(得分:4)

您想使用Cython内存视图。 它们被设计用于在作为同一Cython模块一部分的函数之间传递数组切片。 您可能需要在Cython模块中内联函数以获得完整的性能优势,但这并非总是必要的。 你可以看一下documentation。 我最近给另一个question写了一个相当冗长的答案,它会查看应该使用内存视图的时间。 如果您想更详细地检查为什么切片适用于内存视图,请查看此blog post

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

针对您的具体情况,以下是一些想法: 如果要在Cython模块中的函数之间传递数组切片,则应该能够使用内存视图来传递切片。 这种方法确实依赖于编译时优化,因此如果需要在两个不同时间编译的函数之间传递数组,则必须使用指针在函数之间传递数据。 这意味着要做一些仔细的指针算法,但它仍然可以工作。 如果你需要切片并使用NumPy函数,你可能最终不得不使用NumPy数组,但是值得尝试使用NumPy数组和查看相同数据的内存视图。 这样你就可以将切片作为内存视图传递,而只需要在你真正需要时创建NumPy数组。

另外,我建议将函数func作为一个C函数,以便在调用它时不必经历调用Python函数的开销。 您可以使用cdefcpdef关键字来声明它。 如果您不需要从模块外部调用它,请使用cdef。 如果需要C函数和Python可访问的相应Python包装器,请使用cpdef

答案 1 :(得分:0)

func(my_2d_numpy_array[k:k+1])

切片my_2d_numpy_array而不是索引它可以获得您想要的视图所需的视图。