2012-09-30 10 views
10

私は012dを減らすためにnditerを使う方法を理解しようとしています。私の場合、3d配列を2次元配列に変換します。最初の軸でnumpy.nditerを使って縮小を行う方法

私はここ http://docs.scipy.org/doc/numpy/reference/arrays.nditer.htmlと は、入力の最後の軸 以上の削減を適用する関数を作成するには、管理ヘルプを追いました。しかしこの機能を

def nditer_sum(data, red_axes): 
    it = numpy.nditer([data, None], 
      flags=['reduce_ok', 'external_loop'], 
      op_flags=[['readonly'], ['readwrite', 'allocate']], 
      op_axes=[None, red_axes]) 
    it.operands[1][...] = 0 

    for x, y in it: 
     y[...] = x.sum() 

    return it.operands[1] 
私はdata.sumと同等のものを得ることができます

(軸= 2)だから、

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> nditer_sum(data, [0, 1, -1]) 
[[ 6 22 38] 
[54 70 86]] 
>>> data.sum(axis=2) 
[[ 6 22 38] 
[54 70 86]] 

data.sumと同等のものを得るために(軸= 0)私はその 引数red_axesを[-1、0,1]に変更するには十分でした しかし、結果は全く異なります。 nditer_sum内部forループにおいて

>>> data = numpy.arange(2*3*4).reshape((2,3,4)) 
>>> data.sum(axis=0) 
[[12 14 16 18] 
[20 22 24 26] 
[28 30 32 34]] 
>>> nditer_sum(data, [-1, 0, 1]) 
[[210 210 210 210] 
[210 210 210 210] 
[210 210 210 210]] 

(X、その中のY :)ため、反復子は 12回ループし、アレイを与える2回ループし、長さ12の配列を毎回与え、代わり のさ毎回2の長さです。私は numpyのドキュメントを何度も読んで、これについてはgoogled は役に立たない。私はnumpy 1.6とpython 2.7を使用しています。

+0

-1 op_axesで "新軸" として文書化され、これはあなたがしようとしているものです何をする? また、[None、[size 3]]を押しても、[[size x]、[size y]、[size z]]をop_axesにフィードすることは意図していますか? –

+0

[documentation](http://docs.scipy.org/doc/numpy/reference/generated/numpy.nditer.html)は、「オペランドはイテレータのディメンションからオペランドのディメンションへのマッピングです」 ... それがどのような意味でも。現在の例では、コードを[iterating over arrays tutorial](http://docs.scipy.org/doc/numpy-dev/reference/arrays.nditer.html#reduction-iteration)にコピーしました。これは動作しますが、最後の軸でのみ表示されます。この例では、3d配列にはop_axes None([-1、-1、-1]と同じように見える)があり、2d軸に[0,1、-1] – Sergio

+0

がありますが、[0,1、 1]〜[-1,0,1]は第1軸の縮小を行いますが、動作しません。私の質問は、どのように任意の軸の削減を行うかです。 – Sergio

答えて

0

y[...] = x.sum()y[...] += xに変更すると、(hereのように)修正されます。

+0

しかし、それは私がしたいことではありません。私はxの操作の束を行うより複雑な関数を使用しています。その和の代わりに、 "xの10%低いものと高いものを切り捨てた後の総和"を考えてみましょう。 – Sergio

+0

私はちょうどこの修正により、振る舞いがnumpy.sumと一貫性があり、指定された軸が指定されていると言います。 ..質問に詳細を追加する必要があるかもしれません。 – Benjamin

1

nditerの注文をFに変更すると、ケースが正しく機能します。今度は、あなたが望むように、サイズ(2、)の配列を持つ12のステップがあります。

it = np.nditer([data, None], 
     flags=['reduce_ok', 'external_loop'], 
     op_flags=[['readonly'], ['readwrite', 'allocate']], 
     order='F',  # ADDED to loop starting with the last dimension 
     op_axes=[None, red_axes]) 

しかし、中間のaxis=1の場合、このような解決策はありません。


選択されたディメンションを反復処理するもう1つのアプローチは、縮小された次元の配列に 'multi_index'イテレータを作成することです。私はhttps://stackoverflow.com/a/25097271/901925np.ndindexがこのトリックを使って '浅い繰り返し'を実行することを発見しました。 axis=0ケースでは

、この機能は動作します:

def sum_1st(data): 
    y = np.zeros(data.shape[1:], data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = tuple([slice(None)]+list(it.multi_index)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 

またはいずれかの軸に一般化:

def sum_any(data, axis=0): 
    yshape = list(data.shape) 
    del yshape[axis] 
    y = np.zeros(yshape, data.dtype) 
    it = np.nditer(y, flags=['multi_index']) 
    while not it.finished: 
     xindex = list(it.multi_index) 
     xindex.insert(axis, slice(None)) 
     y[it.multi_index] = data[xindex].sum() 
     it.iternext() 
    return y 
関連する問題