Как правильно объявить массивы numpy в cython

#python #numpy #cython

Вопрос:

Я пытаюсь цитонизировать свой код и удалить как можно больше взаимодействий на python. Я сталкиваюсь с некоторыми проблемами, когда работаю с массивами numpy. У меня есть функция, которая выполняет следующее. Есть некоторые if else операторы и циклы for , которые не показывают никаких взаимодействий с python при использовании %%cython --annotate , и я доволен этим. Однако, несмотря на использование объявления для массива, эти строки кода выделены желтым цветом, указывая на взаимодействие с python.

 cdef func(input1, input2):
    cdef np.ndarray[np.double_t, ndim=2] array = np.zeros((length, 6))
    ...
    "Some computations"

        array[index] = [val1, val2, val3, val4, val5, val6]
     "..."
   array = array[~np.all(array ==0., axis=1)]
   return array
    

    
 

нажав на маленький знак плюс в строке , где написано cdef np.ndarray , я получаю сообщение об ошибке, показанное ниже, к сожалению, у меня недостаточно опыта, чтобы разобраться в этом.

 Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 78, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyInt_From_long(__pyx_v_lenpropen); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_GIVEREF(__pyx_t_2);
  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2);
  __Pyx_INCREF(__pyx_int_6);
  __Pyx_GIVEREF(__pyx_int_6);
  PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_int_6);
  __pyx_t_2 = 0;
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS amp;amp; unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_2, __pyx_t_4) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4);
  __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 78, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 78, __pyx_L1_error)
  __pyx_t_5 = ((PyArrayObject *)__pyx_t_1);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(amp;__pyx_pybuffernd_propen.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, amp;__Pyx_TypeInfo_nn___pyx_t_5numpy_double_t, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {
      __pyx_v_propen = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_propen.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 78, __pyx_L1_error)
    } else {__pyx_pybuffernd_propen.diminfo[0].strides = __pyx_pybuffernd_propen.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_propen.diminfo[0].shape = __pyx_pybuffernd_propen.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_propen.diminfo[1].strides = __pyx_pybuffernd_propen.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_propen.diminfo[1].shape = __pyx_pybuffernd_propen.rcbuffer->pybuffer.shape[1];
    }
  }
  __pyx_t_5 = 0;
  __pyx_v_propen = ((PyArrayObject *)__pyx_t_1);
  __pyx_t_1 = 0;
 

прочитайте учебник здесь
Я думал, что с помощью декораторов @cython.boundscheck(False) # Отключить проверку границ
@cython.wraparound(False) # Деактивировать отрицательную индексацию. может помочь, но это просто не удается скомпилировать полностью

 cdef func(input1, input2):
    @cython.wraparound(False)
    @cython.boundscheck(False)
    cdef np.ndarray[np.double_t, ndim=2] array = np.zeros((length, 6))
    ...
    "Some computations"

        array[index] = [val1, val2, val3, val4, val5, val6]
     "..."
   array = array[~np.all(array ==0., axis=1)]
   return array
 

Комментарии:

1. Декораторы выходят за рамки функции (т. е. стандартный синтаксис Python). Они не будут иметь никакого значения для кода, который вы показываете, но они будут компилироваться.

2. @DavidW Ах да. Спасибо! Сейчас он компилируется, другие проблемы все еще остаются в силе. в строках с участием array по-прежнему отображаются взаимодействия python в аннотированном коде. Я полагаю, что вы правы, тогда проверка границ не была проблемой.

3. array[index] = [val1, val2, val3, val4, val5, val6] требуется создать временный объект массива ( array[index] ) и назначить список ; и массив , и список являются объектами python. Существует несколько способов избежать создания объектов для этого задания. Один из способов-это сделать: array[index,0] = val1; array[index,1] = val2; и так далее.

4. в Cython, поскольку циклы дешевы и быстры, просто используйте один из них для присвоения ваших значений