2012-02-23 26 views
6

我是一個相對有經驗的Python程序員,但在很長一段時間裏沒有寫任何C語言,所以我試圖理解Cython。我正在嘗試編寫一個將在NumPy recarray的列上運行的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柱。它編譯和運行沒有問題。

我的問題是,我會如何修改它,以便它可以在任何列上操作?在上面的例子中,總和列是硬編碼的,並通過點符號訪問。是否有可能改變函數,這樣總和列被作爲參數傳入?

回答

1

你想要什麼需要弱打字,哪些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 
+0

像這樣的東西可能會工作 - 你可以傳遞一個融合的類型作爲running_sum的類型,並將其作爲指針傳遞,然後可以將該類型轉換爲該類型。 – shaunc 2012-05-05 04:16:35

2

我相信這應該可以使用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中關閉boundscheck,wraparoundnonecheckcompiler directives可能會進一步提高速度。