【问题标题】:Return variable length array in Numpy C-extension?在 Numpy C 扩展中返回可变长度数组?
【发布时间】:2011-06-05 05:51:57
【问题描述】:

site 的帮助下,我之前做了一些 Numpy C 扩展,但据我所知,返回的参数都是固定长度的。

有没有办法让 Numpy C 扩展返回一个可变长度的 numpy 数组?

【问题讨论】:

  • 您将什么称为“可变长度 numpy 数组”?据我所知,numpy 数组一旦设置大小就无法调整大小。

标签: python c numpy variable-length-array


【解决方案1】:

我将您的问题解释为“我有一个函数采用长度为 n 的 NumPy 数组,但它会返回另一个长度为 m 的数组,不同于 n。”如果是这种情况,您将需要在扩展中 malloc 一个新的 C 数组,例如

new_array = malloc(m * sizeof(int64)); // or whatever your data type is

然后用它创建一个新的 NumPy 数组。这个例子假设一个一维数组:

int npy_intp dims[1];
dims[0] = m;
PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNewFromData(1,          // 1D array
                                                                dims,       // dimensions
                                                                NPY_INT64,  // type
                                                                new_array);
PyArray_ENABLEFLAGS(out, NPY_ARRAY_OWNDATA);

然后返回新数组。这里重要的部分是设置 NPY_ARRAY_OWNDATA 标志,以便在 Python 对象被垃圾回收时释放您分配的内存。

【讨论】:

    【解决方案2】:

    您可能会发现使用 Numpy C-API 在 Cython 中进行 numpy 扩展更容易,它简化了流程,因为它允许您混合 python 和 c 对象。在这种情况下,制作可变长度数组并不难,您可以简单地指定具有任意形状的数组。

    Cython numpy tutorial 可能是该主题的最佳来源。

    例如,这是我最近写的一个函数:

    import numpy as np
    cimport numpy as np
    cimport cython
    
    dtype = np.double
    ctypedef double dtype_t
    
    np.import_ufunc()
    np.import_array()
    
    def ewma(a, d, axis):
        #Calculates the exponentially weighted moving average of array a along axis using the parameter d.
        cdef void *args[1]
    
        cdef double weight[1]
        weight[0] = <double>np.exp(-d)
    
    
        args[0] = &weight[0]
    
        return apply_along_axis(&ewma_func, np.array(a, dtype = float), np.double, np.double, False, &(args[0]), <int>axis)
    
    cdef void ewma_func(int n, void* aData,int astride, void* oData, int ostride, void** args):
        #Exponentially weighted moving average calculation function 
    
        cdef double avg = 0.0
        cdef double weight = (<double*>(args[0]))[0]
        cdef int i = 0
    
        for i in range(n): 
    
            avg = (<double*>((<char*>aData) + i * astride))[0]*weight + avg * (1.0 - weight) 
    
    
            (<double*>((<char*>oData) + i * ostride))[0] = avg  
    
    ctypedef void (*func_1d)(int, void*, int, void*, int, void **)
    
    cdef apply_along_axis(func_1d function, a, adtype, odtype, reduce,  void** args, int axis):
        #generic function for applying a cython function along a particular dimension
    
        oshape = list(a.shape)
    
        if reduce :
            oshape[axis] = 1
    
        out = np.empty(oshape, odtype)
    
        cdef np.flatiter ita, ito
    
        ita = np.PyArray_IterAllButAxis(a,   &axis)
        ito = np.PyArray_IterAllButAxis(out, &axis)
    
        cdef int axis_length = a.shape[axis]
        cdef int a_axis_stride = a.strides[axis]
        cdef int o_axis_stride = out.strides[axis]
    
        if reduce: 
            o_axis_stride = 0
    
        while np.PyArray_ITER_NOTDONE(ita):
    
            function(axis_length, np.PyArray_ITER_DATA (ita), a_axis_stride, np.PyArray_ITER_DATA (ito), o_axis_stride, args)
    
            np.PyArray_ITER_NEXT(ita)
            np.PyArray_ITER_NEXT(ito)
    
        if reduce:  
            oshape.pop(axis)
            out.shape = oshape
    
        return out  
    

    如果这不适合你,有一个函数可以创建一个任意形状的新空数组 (link)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 2014-02-13
      • 2020-08-29
      • 1970-01-01
      相关资源
      最近更新 更多