2017-01-24 20 views
2

Iが平坦アレイb有する:numpyのインデックス - numpy.argmax.reduceat

a = numpy.array([0, 1, 1, 2, 3, 1, 2]) 

そして各 "チャンク" の開始をマーキングインデックスの配列をc

b = numpy.array([0, 4]) 

私は縮小を使用して、各「チャンク」の最大値を見つけることができます知っている:

m = numpy.maximum.reduceat(a,b) 
>>> array([2, 3], dtype=int32) 

しかし...ベクトル化された操作(リスト、ループなし)を持つ、のような最大<edit>のインデックスを(numpy.argmaxのように)見つける方法はありますか?

+0

私が答えと思っていたので、一時的に私の質問を削除: 'numpy.argmax(numpy.equal.outer(M、A)、軸= 1)'、それは例wherのために動作しません。同じ最大値が複数の場所で発生する... – Benjamin

+0

たとえば、この配列の場合、 'a = numpy.array([0,1,1,3,3,1,2])' 2つのチャンクで発生します。 – Benjamin

+0

問題は 'np.maximum'は' reduceat'を持つ 'ufunc'です。これは効果的に配列全体を反復し、一度に2つの値を比較します。しかし、 'np.max'と' np.argmax'は一度に配列全体を操作する関数です。彼らは 'ufunc'ではありません。 – hpaulj

答えて

1

this postからアイデアを借りてください。関与

ステップ:

  • によって、グループ内のすべての要素をオフセット限界オフセット。これらをグローバルに並べ替えると、各グループがそれぞれのポジションに留まることが制限されますが、各グループ内のエレメントはソートされます。

  • ソートされた配列では、グループmaxである最後の要素を探します。それらのインデックスは、グループの長さをオフセットした後のargmaxになります。

したがって、ベクトル化の実装は次のようになり -

マイナーな微調整として
def numpy_argmax_reduceat(a, b): 
    n = a.max()+1 # limit-offset 
    grp_count = np.append(b[1:] - b[:-1], a.size - b[-1]) 
    shift = n*np.repeat(np.arange(grp_count.size), grp_count) 
    sortidx = (a+shift).argsort() 
    grp_shifted_argmax = np.append(b[1:],a.size)-1 
    return sortidx[grp_shifted_argmax] - b 

と1おそらく速く、我々は代わりのようなので、cumsumshiftを作成するため、それ以前のアプローチのバリエーションを持っている可能性があり -

def numpy_argmax_reduceat_v2(a, b): 
    n = a.max()+1 # limit-offset 
    id_arr = np.zeros(a.size,dtype=int) 
    id_arr[b[1:]] = 1 
    shift = n*id_arr.cumsum() 
    sortidx = (a+shift).argsort() 
    grp_shifted_argmax = np.append(b[1:],a.size)-1 
    return sortidx[grp_shifted_argmax] - b 
+0

私はすでに以前の操作から 'shift 'を持っているので、どちらの解決策も私の場合はうまくいきます。いい答え。 – Benjamin

+0

@ベンジャミンだから、仕事の大半は既に行われている。ニース! – Divakar