Доступ к столбцам массива записей NumPy в Cython - PullRequest
6 голосов
/ 24 февраля 2012

Я относительно опытный программист на 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)

Это просто суммирует столбец f0 в массиве. Компилируется и запускается без проблем.

Мой вопрос: как бы я изменил это, чтобы он мог работать на любом столбце? В приведенном выше примере столбец для суммирования жестко запрограммирован и доступен через точечную запись. Можно ли изменить функцию, чтобы столбец sum передавался как параметр?

Ответы [ 2 ]

2 голосов
/ 30 июля 2013

Я полагаю, что это возможно при использовании памяти 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(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, чтобы указать, что массив можно считать смежным.И, как всегда, после тестирования кода отключение директив компилятора *1002*, wraparound и nonecheck в Cython, вероятно, еще больше увеличит скорость.

1 голос
/ 13 апреля 2012

То, что вы хотите, требует слабой типизации, чего нет у C. Если все типы ваших записей одинаковы, вы можете выполнить что-то вроде:

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
...