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])
    (这可能不是您的意图)

  • 因此,这取决于上下文。

    可能是Numpys
    ma
    模块(用于屏蔽阵列)实现了您想要的功能:

    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)