2016-01-19 14 views
6

私はとのminまたはmax値を得ることができることを知っている(好ましくは平坦化ではありません)。これらの値のインデックスは、次の式で返されます。numpy配列から最大または最小のn要素を取得しますか? numpyの行列/ベクトルのうち、</p> <pre><code>max(matrix) min(matrix) </code></pre> <p>:

argmax(matrix) 
argmin(matrix) 

私は5x5の行列がある場合:

a = np.arange(5*5).reshape(5, 5) + 10 

# array([[10, 11, 12, 13, 14], 
#  [15, 16, 17, 18, 19], 
#  [20, 21, 22, 23, 24], 
#  [25, 26, 27, 28, 29], 
#  [30, 31, 32, 33, 34]]) 

を私は経由して最大値を得ることができます:

In [86]: np.max(a) # getting the max-value out of a 
Out[86]: 34 

In [87]: np.argmax(a) # index of max-value 34 is 24 if array a were flattened 
Out[87]: 24 

...しかし、最大または最小のn要素を取得するための最も効率的な方法は何ですか?

のうちの5つの要素が必要です。これは、それぞれインデックスのために[20, 21, 22, 23, 24]の5つの最高値のために[30, 31, 32, 33, 34]を返さなければなりません。同様に、5つの最低値の場合は[10, 11, 12, 13, 14]、最も低い5つの要素の場合は[0, 1, 2, 3, 4]となります。

これに対して、効率的で妥当な解決策は何でしょうか?

私の最初のアイデアだった平坦化と配列をソートし、最後と最初の5つの値を取ります。その後、元の2Dマトリックスを検索して、それらの値のインデックスを求めます。 この手順はフラット化+ソートの効率はあまり高くありませんが...もっと速いソリューションを知っている人はいますか?

また、元の2D配列のインデックスを取得したいと思います。だから、np.argmax(a)によって返された24の代わりに(4, 4)を持っています。

+1

'np.partition'(インデックスの場合は' np.argpartition')はO(n)です - これはあなたがここで期待できる最高のものだと思います。最初に配列をラベリングする必要があります(これはビューを作成するだけで、パフォーマンス上のペナルティは発生しません)。 'unravel_index'を使って元の配列の2Dインデックスを取得できます。 –

答えて

4

配列内の最大値または最小値のインデックスを取得する標準的な方法は、np.argpartitionを使用することです。この関数はintroselectアルゴリズムを使用し、線形複雑さで実行されます。これは、大規模な配列(通常はO(n log n))の完全ソートよりも優れています。

デフォルトでは、この機能は配列の最後の軸に沿って機能します。アレイ全体を検討するには、ravel()を使用する必要があります。例えば、ここではランダムな配列aです:

>>> a = np.random.randint(0, 100, size=(5, 5)) 
>>> a 
array([[60, 68, 86, 66, 9], 
     [66, 26, 83, 87, 50], 
     [41, 26, 0, 55, 9], 
     [57, 80, 71, 50, 22], 
     [94, 30, 95, 99, 76]]) 

その後(平坦化)2D配列、使用中の5つの最大値のインデックスを取得する:対応する2Dインデックスを取り戻すために

>>> i = np.argpartition(a.ravel(), -5)[-5:] # argpartition(a.ravel(), 5)[:5] for smallest 
>>> i 
array([ 2, 8, 22, 23, 20]) 

aにおけるこれらの位置の、unravel_indexを使用します。

>>> i2d = np.unravel_index(i, a.shape) 
>>> i2d 
(array([0, 1, 4, 4, 4]), array([2, 3, 2, 3, 0])) 

その後i2daのインデックスを作成すると、バックできます

>>> a[i2d] 
array([86, 87, 95, 99, 94]) 
+0

の場合、ソートは速くなります: '%timeit a.ravel.argpartition(-5) - >5.5μs'と '%time a aravel.argsort() - >3.8μsです。もちろん、より大きなアレイでは、これは正しい方法です。 –