2015-05-21 2 views
1

Предположим, у меня есть код Cython с функциями, которые вычисляют скользящее скользящее среднее и возвращает массив того же размера, что и вход (функция добавляет nan для начальной части, но это не важно для проблемы).Запись кодов numpy в cython с неизвестными размерами

Я написал три функции Cython (приведены ниже):

(а) sma_vec для обработки numpy массивов 1-размерности

(б) sma_mat для обработки numpy массивы 2-размерности

(c) третий sma для возврата значений от sma_vec или sma_mat в зависимости от размера. (Моя мотивация в конечном итоге заменить cpdef перед тем sma_vec или sma_mat в cdef так, что код Python видит только функцию sma)

Функция 1 - обрабатывает numpy массивы 1-размерности

cimport cython 
import numpy as np 
cimport numpy as np 
from numpy cimport ndarray as ar 
ctypedef double dtype_t 

@cython.boundscheck(False) 
@cython.wraparound(False) 
cpdef sma_vec(ar[dtype_t, ndim=1] x, int m): 
    cdef int n 
    cdef Py_ssize_t i, j 
    cdef ar[dtype_t, ndim=1] y 
    if m == 1: 
     return x.copy() 
    else: 
     y = np.zeros_like(x) * np.nan 
     n = x.shape[0] 
     if n < m: 
      return y 
     else: 
      for i in range(m-1, n): 
       for j in range(i-m+1, i+1): 
        if j == i-m+1: 
         y[i] = x[j] 
        else: 
         y[i] += x[j] 
       y[i] /= float(m) 
      return y 

Функция 2 - обрабатывает numpy массивы 2-мерных измерений (вызовы Функция 1 для каждой строки ndarray)

@cython.boundscheck(False) 
@cython.wraparound(False) 
cpdef sma_mat(ar[dtype_t, ndim=2] x, int m): 
    cdef int n 
    cdef Py_ssize_t i 
    cdef ar[dtype_t, ndim=2] y 
    if m == 1: 
     return x.copy() 
    else: 
     y = np.zeros_like(x) * np.nan 
     n = x.shape[0] 
     if n < m: 
      return y 
     else: 
      for i in range(0, x.shape[0]): 
       y[i] = sma_vec(x[i], m) 
      return y 

Функция 3-вызовы функций 1 или 2 функции в зависимости от размерности

@cython.boundscheck(False) 
@cython.wraparound(False) 
cpdef sma(ar[dtype_t] x, int m): 
    if x.ndim == 1: 
     return sma_vec(x, m) 
    elif x.ndim == 2: 
     return sma_mat(x, m) 
    else: 
     raise ValueError('Cannot handle more than two dimensions') 

Код проверки

import numpy as np 
import common.movavg as mv 

x1 = np.array([1.0, 1.4, 1.3, 5.3, 2.3]) 
y1 = mv.sma_vec(x1, 3) 
y1a = mv.sma(x1, 3) 

y1 и y1a возвращают array([nan, nan, 1.233333, 2.666667, 2.966667]) правильно

x2 = np.array([[1.0, 1.4, 1.3, 5.3, 2.3], [4.2, 1.3, 2.3, 5.7, -1.3]]) 
y2 = mv.sma_mat(x2, 2) 

y2 возвращается правильно

array([[ nan, 1.2 , 1.35, 3.3 , 3.8 ], 
     [ nan, 2.75, 1.8 , 4. , 2.2 ]]) 

Но когда я пытаюсь:

y2a = mv.sma(x2, 2) 

Я получаю сообщение об ошибке:

Traceback (most recent call last): 
    File "C:\PF\WinPython-64bit-3.4.2.4\python-3.4.2.amd64\lib\site-packages\IPython\core\interactiveshell.py", line 2883, in run_code 
exec(code_obj, self.user_global_ns, self.user_ns) 
    File "<ipython-input-4-dc092e343714>", line 3, in <module> 
    y2a = mv.sma(x2, 2) 
    File "movavg.pyx", line 54, in movavg.sma (stat\movavg.c:2206) 
ValueError: Buffer has wrong number of dimensions (expected 1, got 2) 

В функции sma, вопрос, кажется, что ar[dtype_t] x (т.е. np.ndarray[double] x) автоматически принимает x.ndim должен иметь размер 1.

Как переписать функцию sma так, чтобы она могла принимать np.ndarray с неизвестными размерами?

+0

Похоже, ошибка копирования вставки: вы вызываете вектор после ваш чек на 'x.ndim == 2':' elif x.ndim == 2: return sma_vec (x, m) '. Измените это на' return sma_mat (x, m) ', и вам должно быть хорошо идти. – Evert

+0

спасибо, что указали его. Я изменил его, но код неожиданно дает ту же ошибку – uday

+0

Просто, чтобы проверить, но вы перекомпилировали его после внесения изменений? – Evert

ответ

1

нашел ответ.

С этой ссылкой: numpy_tutorial, "..." ndim "ключевое слово-аргумент, если не предусмотрено, то одномерный предполагается ..."

Решение заключается в преобразовании функции 3 в:.

@cython.boundscheck(False) 
@cython.wraparound(False) 
cpdef sma(ar x, int m): 
    if x.ndim == 1: 
     return sma_vec(x, m) 
    elif x.ndim == 2: 
     return sma_mat(x, m) 
    else: 
     raise ValueError('Cannot handle more than two dimensions') 

Нам нужно удалить все в [] полностью

Смежные вопросы