Cython:缓冲区dtype不匹配,期望'int'但是得到了Python对象

问题描述 投票:1回答:2

我有一个看起来像这样的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对象

这可能是因为数组中存在Nones,因为将它们修改为0s会消除错误。但None的存在不应该成为问题,如下所示:Cython Extension Types

那么发生了什么?有这个快速的解决方案吗?

python cython
2个回答
1
投票

dtype这样的numpy数组的np.array([1, None])objectint[:,::1]期望int的缓冲区,但得到object的缓冲区,这就是错误说。

如何纠正这个问题应该取决于具体情况,具体来说,None是什么意思?

  1. 您可以将Nones设置为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])(这可能不是您的意图)

所以,这取决于具体情况。


0
投票

Numpys ma模块(用于Masked Array)可能会做你想要的:

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,因此您可以创建ints的二维数组和一维数组行长度(qdxswpois的一维数组) )。然后你会忽略行长以外的任何东西。


可能值得强调的是为什么你不能将int存储在None数组中 - 为了获得使用int数组的速度和空间效率,Numpy只分配存储数字所需的空间。存储int将涉及为每个数字分配一点额外的空间来说“实际上这个是不同的类型”,并且对于每个操作在它之前进行检查“这个数字实际上是一个数字吗?”。可以想象,快速变得低效。

© www.soinside.com 2019 - 2024. All rights reserved.