2017-05-09 61 views
2

似乎在numba中不受支持。在numba jitted函数中动态增长阵列

在nopython模式下使用numba.jit动态增长数组的最佳方式是什么?

到目前为止,我能做的最好的事情是定义并调整jitted函数之外的数组的大小,是否有更好的(和更整齐的)选项?

回答

5

numpy.resizepure python function

import numpy as np 

def resize(a, new_shape): 
    """I did some minor changes so it all works with just `import numpy as np`.""" 
    if isinstance(new_shape, (int, np.core.numerictypes.integer)): 
     new_shape = (new_shape,) 
    a = np.ravel(a) 
    Na = len(a) 
    if not Na: 
     return np.zeros(new_shape, a.dtype) 
    total_size = np.multiply.reduce(new_shape) 
    n_copies = int(total_size/Na) 
    extra = total_size % Na 

    if total_size == 0: 
     return a[:0] 

    if extra != 0: 
     n_copies = n_copies+1 
     extra = Na-extra 

    a = np.concatenate((a,)*n_copies) 
    if extra > 0: 
     a = a[:-extra] 

    return np.reshape(a, new_shape) 

对于一维数组,这将是直着自己实现。不幸的是,ND阵列要复杂得多,因为一些操作在nopython numba函数中不受支持:isinstance,reshape和元组乘法。这里是1D相当于:

import numpy as np 
import numba as nb 

@nb.njit 
def resize(a, new_size): 
    new = np.zeros(new_size, a.dtype) 
    idx = 0 
    while True: 
     newidx = idx + a.size 
     if newidx > new_size: 
      new[idx:] = a[:new_size-newidx] 
      break 
     new[idx:newidx] = a 
     idx = newidx 
    return new 

,当你不希望这样“重复输入”行为,只会用它来增加大小那就更简单了:

@nb.njit 
def resize(a, new_size): 
    new = np.zeros(new_size, a.dtype) 
    new[:a.size] = a 
    return new 

这些功能都装饰与numba.njit,因此可以在nopython模式中的任何numba函数中调用。


注意的一点是,虽然:一般来说,你不想来调整 - 或者如果你然后确保你选择有amoritzed O(1) cost (Wikipedia link)的方法。如果你可以估计最大长度,那么最好立即预先分配一个正确大小(或略微超额分配)的数组。

+0

谢谢,那就是我一直在寻找的。太糟糕了,ND阵列没有简单的解决方案。 – nivniv

+1

您可以使用np.empty(new_size,a.dtype)代替非常小且有争议的性能增益。 – tal

1

通常,我使用的策略是只分配足够多的数组存储以适应计算,然后跟踪最终使用的索引/索引,然后在返回之前将数组切片降至实际大小。这假定您事先知道您可能将阵列增长到的最大大小。我的想法是,在我的大多数应用程序中,内存很便宜,但是调整大小并在python和jitted函数之间切换很贵。

+0

谢谢,我每次调整数组的大小为2倍,所以我最终在python和jitted函数之间切换了log(max_size)。你认为这种转换量是一个真正的瓶颈吗?一个真正的问题是每次拷贝数组的1.5倍,我很乐意摆脱它,但我想这是不知道最大大小的代价(我可能只是用一个荒谬的初始大小来使用你的黑客,只要它适合RAM)。 – nivniv

+0

如果没有真正分析代码,很难说出什么可能是瓶颈(cProfile和line_profiler真的和timeit一样有用)。这实际上取决于你的特定应用。 – JoshAdel