2012-02-23 37 views
6

Tôi là một lập trình viên Python tương đối có kinh nghiệm, nhưng chưa viết bất kỳ C nào trong một thời gian rất dài và đang cố gắng hiểu Cython. Tôi đang cố gắng để viết một chức năng Cython sẽ hoạt động trên một cột của một NumPy recarray.Truy cập cột mảng bản ghi NumPy trong Cython

Mã tôi có cho đến nay là bên dưới.

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 

Tại cửa sổ thông dịch viên:

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

này chỉ đơn giản là tóm tắt các f0 cột của recarray. Nó biên dịch và chạy mà không có vấn đề gì.

Câu hỏi của tôi là, tôi sẽ sửa đổi điều này để nó có thể hoạt động như thế nào trên bất kỳ cột nào? Trong ví dụ trên, cột tổng hợp được mã hóa cứng và truy cập thông qua ký hiệu dấu chấm. Có thể thay đổi hàm để cột tổng hợp được chuyển thành tham số không?

Trả lời

1

Điều bạn muốn yêu cầu nhập sai, mà C không có. Nếu tất cả các loại bản ghi của bạn giống nhau, bạn có thể rút ra một cái gì đó như: (từ chối trách nhiệm Tôi không có Cython trên máy này vì vậy tôi đang mã hóa mù).

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

một cái gì đó như thế này có thể làm việc - bạn có thể vượt qua trong một loại hợp nhất là loại running_sum, và vượt qua nó trong như một con trỏ, sau đó các diễn viên có thể là loại đó. – shaunc

2

Tôi tin rằng điều này có thể thực hiện được bằng cách sử dụng memoryviews của Cython. Nội dung nào đó dọc theo các dòng này sẽ hoạt động (mã không được kiểm tra):

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 

Tốc độ có thể tăng lên bằng cách đảm bảo mảng bản ghi bạn chuyển tới Cython tiếp giáp. Ở phía trăn (gọi), bạn có thể sử dụng np.require, trong khi chữ ký hàm sẽ thay đổi thành rec_cell0[::1] recview để cho biết rằng mảng có thể được giả định là tiếp giáp. Và như thường lệ, khi mã đã được kiểm tra, tắt boundscheck, wraparoundnonecheckcompiler directives trong Cython sẽ có khả năng cải thiện thêm tốc độ.

Các vấn đề liên quan