2017-05-09 14 views
2

numbaではnumpy.resizeがサポートされていないようです。numbaの関数で動的に配列を配列する

numba.jitで動的に成長するアレイをnopythonモードで使用する最良の方法は何ですか?

これまでのところ私ができることは、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) 

1Dアレイでは、これは自分で実装する単純明快になります。残念ながら、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