Cython:缓冲区dtype不匹配,应为'int',但有Python对象

时间:2019-04-21 01:24:50

标签: 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函数:

cpdef y(int[:,::1] x):
...

这引发了错误:ValueError:缓冲区dtype不匹配,应为'int',但有Python对象

这很可能是由于数组中存在None s,因为将它们修改为0 s会消除错误。但是None的存在不应该构成问题,就像这里写的:Cython Extension Types

那么,这是怎么回事?有一个快速的解决方案吗?

2 个答案:

答案 0 :(得分:0)

诸如dtype之类的numpy数组的np.array([1, None])objectint[:,::1]期望有int的缓冲区,但是得到object的缓冲区,这就是错误所在。

如何更正此情况取决于上下文,具体地说,None是什么意思?

  1. 您可以将None设置为0,然后将数组转换为int数组
a = np.array([[1, None]])
a[a==None] = 0
a = a.astype(np.int)
f(a) # then deal with 0
  1. 或者您可以将cython函数签名更改为f(double[:, ::1])
a = np.array([[1, None]])
a = a.astype(np.float)
# a will be np.array([1.0, nan]),
# then deal with nan...
f(a)
  1. 或者您可以将cython函数签名更改为f(object[:, ::1])(这可能不是您的意图)

所以,这取决于上下文。

答案 1 :(得分:0)

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)

由于Cython对int8的处理不好,因此我将其视为dtype=np.bool


您还可以考虑创建自己的数据结构-例如,看起来总是None的行的末尾,因此您可以创建int的2D数组,一维数组的行长(int的一维数组)。然后,您将忽略行长以外的任何内容。


可能值得强调为什么不能将None存储在int数组中-为了获得使用int数组的速度和空间效率,然后Numpy仅分配存储数字所需的空间。存储None会涉及为每个数字分配一点额外的空间,以便说“实际上这个数字是不同的类型”,并且每个操作之前都要检查“这个数字实际上是数字吗? ”。您可以想象很快就会变得效率低下。