2017-09-06 10 views
0

私は4次元配列を持っていますが、最後の2次元を反復して2次元スライスを作成する関数を適用したいと思います。 Vizは(x、y、0,0)にf(2d_array)を、(x、y、0,1)などにf(2d_array)を適用します。同じであるが、一般的な解は、形状の配列(x '、y'、w、z)を返す。ここでwとzは元の配列の最後の2つの次元である。numpyはn個の空白に沿って適用します

これは明らかにnDアレイ上のmDスライスに一般化できます。

このことを行う組み込みの機能はありますか?

+0

すべてのドキュメントを確認しましたか? – wwii

答えて

1

「基本」適用-に沿って軸モデルは一つの軸に反復し、あなたの関数に他を渡すことです:

In [197]: def foo(x):   # return same size 
    ...:  return x*2 
    ...: np.array([foo(x) for x in np.arange(12).reshape(3,4)]) 
    ...: 
Out[197]: 
array([[ 0, 2, 4, 6], 
     [ 8, 10, 12, 14], 
     [16, 18, 20, 22]]) 
In [198]: def foo(x): 
    ...:  return x.sum() # return one less dim 
    ...: np.array([foo(x) for x in np.arange(12).reshape(3,4)]) 
    ...: 
Out[198]: array([ 6, 22, 38]) 
In [199]: def foo(x): 
    ...:  return x.sum(keepdims=True) # condense the dim 
    ...: np.array([foo(x) for x in np.arange(12).reshape(3,4)]) 
    ...: 
Out[199]: 
array([[ 6], 
     [22], 
     [38]]) 

あなたの4Dの問題は、これを合わせてマッサージすることができます。行うのと等価である

In [200]: arr_4d = np.arange(24).reshape(2,3,2,2) 
In [201]: arr_2d = arr_4d.reshape(6,4).T 
In [202]: res = np.array([foo(x) for x in arr_2d]) 
In [203]: res 
Out[203]: 
array([[60], 
     [66], 
     [72], 
     [78]]) 
In [204]: res.reshape(2,2) 
Out[204]: 
array([[60, 66], 
     [72, 78]]) 

In [205]: arr_4d[:,:,0,0].sum() 
Out[205]: 60 
In [206]: foo(arr_4d[:,:,0,0].ravel()) 
Out[206]: array([60]) 

apply_along_axisは1Dアレイを取る機能を必要とするが、このようにして適用することができる。

In [209]: np.apply_along_axis(foo,0,arr_4d.reshape(6,2,2)) 
Out[209]: 
array([[[60, 66], 
     [72, 78]]]) 

fooはにその入力を作り直すことができ2dをとり、2dをとる関数に渡します。 apply_along_indexは、反復軸のインデックスを生成するためにnp.ndindexを使用します。

In [212]: list(np.ndindex(2,2)) 
Out[212]: [(0, 0), (0, 1), (1, 0), (1, 1)] 

np.vectorizeは、通常、スカラーを取る関数で動作します。しかし、最近のバージョンにはsignatureというパラメータがあります。これはあなたのケースを扱うために使うことができると思います。それは最初の2つの軸を反復し、最後の2つを関数に渡すように入力を転置する必要があります。私の答えはhttps://stackoverflow.com/a/46004266/901925です。これらのアプローチの

なし速度の利点を提供しています。整形またはスワップなし


、私はndindexの助けを借りて繰り返すことができます。

は、2D入力を期待する関数を定義します:arr_4dの最後の2薄暗いため

def foo2(x): 
    return x.sum(axis=1, keepdims=True) # 2d 

インデックス反復子:

In [260]: idx = np.ndindex(arr_4d.shape[-2:]) 

は、リターンの形状を決定するためにテストCALCを行います。 vectorizeapply...この種のテストを行います。

In [261]: r1 = foo2(arr_4d[:,:,0,0]).shape 
In [262]: r1 
Out[262]: (2, 1) 

結果配列:

In [263]: res = np.zeros(r1+arr_4d.shape[-2:]) 
In [264]: res.shape 
Out[264]: (2, 1, 2, 2) 

今反復:

In [265]: for i,j in idx: 
    ...:  res[...,i,j] = foo2(arr_4d[...,i,j]) 
    ...:  
In [266]: res 
Out[266]: 
array([[[[ 12., 15.], 
     [ 18., 21.]]], 


     [[[ 48., 51.], 
     [ 54., 57.]]]]) 
0

numpy.apply_over_axesのようなものを探して、forのループを組み合わせて、さまざまな軸を繰り返し処理していると思います。

+0

'numpy.apply_over_axes'は、一度に1つの軸に関数を適用するようです。私は同時に複数の軸に関数を適用しようとしています。 – Scott

+0

実際にapply_along_axisは1-dのみの関数を使用しますが、apply_over_axesは複数軸を使用します。関数の簡単な説明は、「関数を複数の軸に繰り返し適用する」です。 – FabienP

0

私は自分の圧延。私は、これと@ hpauljの方法の間にパフォーマンスの違いがあるかどうか、またカスタムcモジュールを書くことが重要な改善をもたらすと信じる理由があるかどうかを知ることに興味があります。もちろん、@ hpauljのメソッドはより一般的です。なぜなら、これは配列の操作をただちに実行する必要があるからです。

def apply_along_space(f, np_array, axes): 
    # apply the function f on each subspace given by iterating over the axes listed in axes, e.g. axes=(0,2) 
    for slic in itertools.product(*map(lambda ax: range(np_array.shape[ax]) if ax in axes else [slice(None,None,None)], range(len(np_array.shape)))): 
     f(np_array[slic]) 
    return np_array 
関連する問題