Cython: несоответствие буфера dtype, ожидалось int, но получен объект Python - PullRequest
1 голос
/ 21 апреля 2019

У меня есть 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

Итак, что происходит?Есть ли быстрое решение для этого?

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

Массив dtype, например np.array([1, None]), равен object. int[:,::1] ожидаем буфер int, но получим буфер object, это говорит об ошибке.

Как это исправить, зависит от контекста, в частности, что означает None?

  1. Вы можете установить None s в 0, а затем преобразовать массив в int array
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 голосов
/ 22 апреля 2019

Возможно, что модуль 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, так что вы можете создать двумерный массив размером int с и длиной строки одномерного массива (одномерный массив int с).Затем вы проигнорируете что-либо, кроме длины строки.


Вероятно, стоит подчеркнуть, почему вы не можете хранить None в массиве int - чтобы получить скорость и эффективность использования пространстваиспользуя массив int, Numpy выделяет только место, необходимое для хранения чисел.Для хранения None потребуется выделить немного дополнительного пространства для каждого числа, чтобы сказать «на самом деле это другой тип», и для каждой операции иметь перед ним проверку на «действительно ли это число - число?».Как вы можете себе представить, это быстро становится неэффективным.

...