[英]Using numpy.array in cython
我想以cython格式重寫一個類,並將其另存為demo.pyx。 該類的輸入參數將是具有Nx2
形狀的2D np.array ,例如a=np.array([[0.2,-0.8],[3.7,0.02],..,[-0.92,-3.33]])
或列表, instance a=[0.1,2.7]
。
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef unsigned double *x
cdef unsigned double *y
def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
self.x = &positions[:,0]
self.y = &positions[:,1]
我嘗試寫的內容導致錯誤消息如下:
running build_ext
cythoning demo.pyx to demo.c
Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef unsigned double *x
^
------------------------------------------------------------
demo.pyx:5:9: Unrecognised type modifier combination
Error compiling Cython file:
------------------------------------------------------------
...
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef unsigned double *x
cdef unsigned double *y
^
------------------------------------------------------------
demo.pyx:6:9: Unrecognised type modifier combination
Error compiling Cython file:
------------------------------------------------------------
...
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef unsigned double *x
cdef unsigned double *y
def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
self.x = &positions[:,0]
^
------------------------------------------------------------
demo.pyx:8:17: Cannot take address of Python variable
Error compiling Cython file:
------------------------------------------------------------
...
cdef class halo_positions(object):
cdef unsigned double *x
cdef unsigned double *y
def __init__(self, np.ndarray[np.float64_t,ndim=2,mode='c'] positions):
self.x = &positions[:,0]
self.y = &positions[:,1]
^
------------------------------------------------------------
demo.pyx:9:17: Cannot take address of Python variable
我知道使用指針的方式存在問題,但是如果我想使x
和y
的類型不明確,則需要使用它。 我怎樣才能使我的class
工作?
當您進行positions[:,0]
或positions[:,1]
您將在Cython中創建一個新的,1D且未聲明的緩沖區。 這不是您可以從中獲取地址的元素。 該地址將對應於數組中的單個值,因此您應該執行以下操作:
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef double *x
cdef double *y
def __init__(self, np.ndarray[np.float64_t, ndim=2, mode='c'] positions):
cdef np.ndarray[np.float64_t, ndim=1] buffx, buffy
buffx = positions[:,0].copy()
buffy = positions[:,1].copy()
self.x = &buffx[0]
self.y = &buffy[0]
注意:
是的 ,您可以獲取數組中元素的地址並將其用作double *
數組,例如對於b=&positions[0,0]
; positions[0,0]==b[0]
和positions[0,0+1]==b[1]
; 當positions
是C連續的2D數組時。 您不是將np.ndarray
轉換為double *
,而是直接從內存訪問其數據;
我正在使用.copy()
來保證您的內存中有連續的數據。 如果positions
是Fortran連續的,這將是不必要的。
&
運算符采用對象的地址。 您想要將self.x
分配為positions[0]
的地址。 所以應該是self.x = &position[0]
。 這將設置為x的self成員讀取為位置的第0個元素的地址。 您嘗試做的是將x的地址設置為某物。 但是您不允許這樣做。 &
只允許在等式的右邊。
Cython無法將numpy數組轉換為double *
,可以改用double[:]
,例如:
cimport numpy as np
cdef class halo_positions(object):
cdef double *x
cdef double *y
def __init__(self, double[:] positions):
self.x = &positions[0]
self.y = &positions[1]
def debug(self):
print self.x[0], self.y[0]
但這很危險:
a = np.array([1.0, 2.0, 3.0, 4.0])
hp = halo_positions(a)
hp.debug()
del a
hp.debug() # x and y is wild pointer now.
也許您應該在halo_positions
類中保留對positions
的引用。
您的代碼有幾個問題。 首先,最容易修復的是,沒有諸如“ unsigned double”之類的東西,因此您應該從一開始就刪除unsigned
。
另外, &positions[:,0]
也不是獲取數組地址的正確語法,因為:
將返回Python對象。 您需要執行&positions[0,0]
,它指向數組的初始元素。
應該指出的是,您的__init__
僅適用於Numpy數組,不適用於列表,如您聲明的那樣。 您必須事先將任何列表轉換為數組。 還請記住,您需要保持對通過其指針使用的任何數組的有效引用,否則將遇到麻煩。
通常,根據您想對代碼執行的操作,在類中使用指針變量可能不是最安全的選擇。
我從google的cython.group獲得的答案非常有效:
import cython
cimport cython
import numpy as np
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cdef class halo_positions(object):
cdef double [:] _x
property x:
def __get__(self):
return np.array(self._x)
def __set__(self, np.ndarray[DTYPE_t, ndim=1] x):
self._x = x
cdef double [:] _y
property y:
def __get__(self):
return np.array(self._y)
def __set__(self, np.ndarray[DTYPE_t, ndim=1] y):
self._y = y
def __init__(self, np.ndarray[DTYPE_t,ndim=2] positions):
self._x = positions[:,0]
self._y = positions[:,1]
def debug(self):
print self.x, self.y
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.