Cython:缓冲区数据类型不匹配,应为';int';但是得到了Python对象
我有一个Cython:缓冲区数据类型不匹配,应为';int';但是得到了Python对象,python,cython,Python,Cython,我有一个np.ndarray如下所示: print(x) [[1 3 None None None None] [0 2 3 4 None None] [1 5 4 None None None] [1 6 0 4 None None] [7 6 5 1 3 2] [4 7 2 8 None None] [7 4 3 None None None] [4 6 8 5 None None] [7 5 None None None None]] 我将其提供给cython函数,定义如
np.ndarray
如下所示:
print(x)
[[1 3 None None None None]
[0 2 3 4 None None]
[1 5 4 None None None]
[1 6 0 4 None None]
[7 6 5 1 3 2]
[4 7 2 8 None None]
[7 4 3 None None None]
[4 6 8 5 None None]
[7 5 None None None None]]
我将其提供给cython函数,定义如下:
cpdef y(int[:,::1] x):
...
这会引发错误:ValueError:Buffer数据类型不匹配,预期为“int”,但得到了Python对象
这可能是因为数组中存在None
s,因为将它们修改为0
s会删除错误。但是,None
的存在不应该造成问题,如本文所述:
那么,到底发生了什么?有没有快速的解决方法?numpy数组的
dtype
,例如np。数组([1,None])
是对象
int[:,::1]
期望缓冲区为int
,但得到对象的缓冲区,这就是错误
如何纠正这一点应取决于上下文,具体来说,None
是什么意思
您可以将None
s设置为0,然后将数组转换为int
数组
或者您可以将cython函数签名更改为f(double[:,::1])
或者您可以将cython函数签名更改为f(对象[:,::1])
(这可能不是您的意图)
因此,这取决于上下文。可能是Numpysma
模块(用于屏蔽阵列)实现了您想要的功能:
x = np.ma.array([[1, 3, 0, 0, 0, 0],
[0, 2, 3, 4, 0, 0]],
dtype=np.int,
mask=[[0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1]]) # True is "masked out"
在Cython中,您将其拆分为数据和掩码
def y(x):
cdef int[:,::1] x_data = x.data
cdef int8_t[:,::1] x_mask = x.mask.view(dtype=np.int8)
我把它看作是int8
,因为Cython不能很好地处理dtype=np.bool
您还可以考虑创建自己的数据结构-例如,看起来总是行的末尾是None
,因此您可以创建一个包含int
s的2D数组和一个1D数组行长度(一个包含int
s的1D数组)。然后忽略行长度以外的任何内容
可能值得强调的是,为什么不能在int
数组中存储None
——为了获得使用int
数组的速度和空间效率,Numpy只分配存储数字所需的空间。存储None
需要为每个数字分配一点额外的空间,以表示“实际上这个数字是不同的类型”,并在每个操作之前检查“这个数字实际上是一个数字吗?”。正如您所想象的那样,它很快就会变得低效。Numpy数组,比如a=np.array([1,None])
,a.dtype
是object
,这就是问题所在,int[:,::1]
需要一个int缓冲区,但却有一个对象缓冲区,文档读起来好像整个变量都可以是None
,然而,您有一个由int
和non-int
/None
值组成的数组,这是无效的。那么,是否有一个简单的更正方法?我可以将None
s键入整数吗?还是我只需要将None
s转换成一些int
值?
x = np.ma.array([[1, 3, 0, 0, 0, 0],
[0, 2, 3, 4, 0, 0]],
dtype=np.int,
mask=[[0, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 1]]) # True is "masked out"
def y(x):
cdef int[:,::1] x_data = x.data
cdef int8_t[:,::1] x_mask = x.mask.view(dtype=np.int8)