2012-02-23 13 views
6

Jestem stosunkowo doświadczonym programistą Pythona, ale nie napisałem żadnego C w bardzo długim czasie i próbuję zrozumieć Cython. Próbuję napisać funkcję Cython, która będzie działać na kolumnie recarray NumPy.Dostęp do kolumn tablicy rekordów NumPy w Cython

Kod, który do tej pory znajduję się poniżej.

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 

W wierszu tłumacza:

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

To po prostu sumuje kolumnę recarray f0. Kompiluje i działa bez problemu.

Moje pytanie brzmi, w jaki sposób zmodyfikować to tak, aby działało w dowolnej kolumnie? W powyższym przykładzie kolumna do sumy jest zakodowana i dostępna za pośrednictwem notacji kropkowej. Czy jest możliwa zmiana funkcji, aby kolumna na sumę została przekazana jako parametr?

Odpowiedz

1

Czego chcesz, wymaga słabego pisania, którego C nie ma. Jeśli wszystkie twoje typy rekordów są takie same, być może uda ci się wyciągnąć coś takiego: (zrzeczenie się, że nie mam Cythona na tej maszynie, więc koduję niewidomych).

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 
+0

coś podobnego może działać - możesz przekazać w postaci topionego jako typ running_sum i przekazać go jako wskaźnik, a następnie rzutowania może być do tego typu. – shaunc

2

Uważam, że powinno to być możliwe przy użyciu Cittona memoryviews. Coś wzdłuż tych linii powinny działać (kod nie testowane):

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 

Prędkość można prawdopodobnie zwiększona poprzez zapewnienie, że tablica rekord przechodzą do Cython jest ciągłe. Po stronie Pythona (wywoływanie) można użyć np.require, podczas gdy sygnatura funkcji powinna zmienić się na rec_cell0[::1] recview, aby wskazać, że tablica może być przyległa. Jak zwykle, po przetestowaniu kodu, wyłączenie w Cython , i prawdopodobnie poprawi prędkość.