【问题标题】:Accessing NumPy record array columns in Cython在 Cython 中访问 NumPy 记录数组列
【发布时间】:2012-02-23 23:36:22
【问题描述】:

我是一个相对有经验的 Python 程序员,但很长时间没有写过任何 C 语言,我正在尝试理解 Cython。我正在尝试编写一个 Cython 函数,该函数将对 NumPy 重新数组的列进行操作。

我目前的代码如下。

recarray_func.pyx:

import numpy as np
cimport numpy as np

cdef packed struct rec_cell0:
  np.float32_t f0
  np.int64_t i0, i1, i2

def sum(np.ndarray[rec_cell0, ndim=1] recarray):
    cdef Py_ssize_t i
    cdef rec_cell0 *cell
    cdef np.float32_t running_sum = 0

    for i in range(recarray.shape[0]):
        cell = &recarray[i]
        running_sum += cell.f0
    return running_sum

在解释器提示下:

array = np.recarray((100, ), names=['f0', 'i0', 'i1', 'i2'],
                             formats=['f4', 'i8', 'i8', 'i8'])
recarray_func.sum(array)

这只是对recarray 的f0 列求和。它编译和运行没有问题。

我的问题是,我将如何修改它以便它可以在任何列上运行?在上面的示例中,要求和的列是硬编码的,并通过点表示法访问。是否可以更改函数,以便将要求和的列作为参数传入?

【问题讨论】:

    标签: python numpy cython


    【解决方案1】:

    我相信使用 Cython 的 memoryviews 应该可以做到这一点。这些方面的东西应该可以工作(代码未经测试):

    import numpy as np
    cimport numpy as np
    
    cdef packed struct rec_cell0:
      np.float32_t f0
      np.int64_t i0, i1, i2
    
    def sum(rec_cell0[:] recview):
        cdef Py_ssize_t i
        cdef np.float32_t running_sum = 0
    
        for i in range(recview.shape[0]):
            running_sum += recview[i].f0
        return running_sum
    

    通过确保传递给 Cython 的记录数组是连续的,可能会提高速度。在python(调用)端,您可以使用np.require,而函数签名应更改为rec_cell0[::1] recview,以表明可以假定数组是连续的。与往常一样,一旦代码经过测试,在 Cython 中关闭 boundscheckwraparoundnonecheck compiler directives 可能会进一步提高速度。

    【讨论】:

      【解决方案2】:

      你想要的需要弱类型,而 C 没有。如果您所有的记录类型都相同,您可能会得到类似的结果:(免责声明我在这台机器上没有 Cython,所以我在编码盲人)。

      import numpy as np
      cimport numpy as np
      
      cdef packed struct rec_cell0:
        np.float32_t f0
        np.int64_t i0, i1, i2
      
      def sum(np.ndarray[rec_cell0, ndim=1] recarray, colname):
          cdef Py_ssize_t i
          cdef rec_cell0 *cell
          cdef np.float32_t running_sum = 0
      
          loc = recarray.dtype.fields[colname][1]
      
          for i in range(recarray.shape[0]):
              cell = &recarray[i]
              running_sum += *(int *)(&cell+loc);
          return running_sum
      

      【讨论】:

      • 这样的事情可能会奏效——你可以传入一个融合类型作为 running_sum 的类型,并将其作为指针传入,然后强制转换为该类型。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-17
      相关资源
      最近更新 更多