web-dev-qa-db-ja.com

NumPy配列で最大値Nのインデックスを得るにはどうすればいいですか?

NumPyはnp.argmaxを介して配列の最大値のインデックスを取得する方法を提案します。

私は似たようなことをしたいのですが、Nの最大値のインデックスを返します。

例えば、私が配列を持っているとすると、[1, 3, 2, 4, 5]function(array, n=3)は要素[4, 3, 1]に対応するインデックス[5, 4, 3]を返します。

363

私が思い付くことができた最も簡単なものは、次のとおりです。

In [1]: import numpy as np

In [2]: arr = np.array([1, 3, 2, 4, 5])

In [3]: arr.argsort()[-3:][::-1]
Out[3]: array([4, 3, 1])

これは配列の完全な種類を含みます。 numpyが部分的なソートを行うための組み込みの方法を提供するのではないかと思います。今のところ私は見つけることができませんでした。

この解決方法が遅すぎることが判明した場合(特に小さいnの場合)、 Cython でコードを書くことを検討する価値があります。

262
NPE

新しいNumPyバージョン(1.8以降)には、このために argpartition という名前の関数があります。 4つの最も大きい要素のインデックスを得るために、

>>> a = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
>>> a
array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
>>> ind = np.argpartition(a, -4)[-4:]
>>> ind
array([1, 5, 8, 0])
>>> a[ind]
array([4, 9, 6, 9])

argsortとは異なり、この関数は最悪の場合線形時間で実行されますが、a[ind]の評価結果からわかるように、返されるインデックスはソートされません。あなたもそれが必要な場合は、後でそれらを並べ替えます。

>>> ind[np.argsort(a[ind])]
array([1, 8, 5, 0])

このようにソートされた順序で先頭の - k 要素を取得するには、O( n + k log k )の時間がかかります。

456
Fred Foo

もっとシンプル:

idx = (-arr).argsort()[:n]

n は最大値の数です。

36
Ketan

つかいます:

>>> import heapq
>>> import numpy
>>> a = numpy.array([1, 3, 2, 4, 5])
>>> heapq.nlargest(3, range(len(a)), a.take)
[4, 3, 1]

通常のPythonリストの場合:

>>> a = [1, 3, 2, 4, 5]
>>> heapq.nlargest(3, range(len(a)), a.__getitem__)
[4, 3, 1]

Python 2を使用している場合は、xrangeではなくrangeを使用してください。

出典:heapq - ヒープキューアルゴリズム

27
anishpatel

多次元配列で作業している場合は、インデックスを平坦化して解明する必要があります。

def largest_indices(ary, n):
    """Returns the n largest indices from a numpy array."""
    flat = ary.flatten()
    indices = np.argpartition(flat, -n)[-n:]
    indices = indices[np.argsort(-flat[indices])]
    return np.unravel_index(indices, ary.shape)

例えば:

>>> xs = np.sin(np.arange(9)).reshape((3, 3))
>>> xs
array([[ 0.        ,  0.84147098,  0.90929743],
       [ 0.14112001, -0.7568025 , -0.95892427],
       [-0.2794155 ,  0.6569866 ,  0.98935825]])
>>> largest_indices(xs, 3)
(array([2, 0, 0]), array([2, 2, 1]))
>>> xs[largest_indices(xs, 3)]
array([ 0.98935825,  0.90929743,  0.84147098])
24
danvk

K番目に大きい要素のorderを気にしない場合は、 argpartition を使用できます。 argsortによる完全なソートよりも。

K = 4 # We want the indices of the four largest values
a = np.array([0, 8, 0, 4, 5, 8, 8, 0, 4, 2])
np.argpartition(a,-K)[-K:]
array([4, 1, 5, 6])

クレジットは この質問 に移動します。

いくつかのテストを実行しましたが、配列のサイズとKの値が大きくなると、argpartitionargsortを上回るように見えます。

9
blue

多次元配列の場合、期待される軸に沿って分割を適用するためにaxisキーワードを使用できます。

# For a 2D array
indices = np.argpartition(arr, -N, axis=1)[:, -N:]

そしてアイテムをつかむために:

x = arr.shape[0]
arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N)

しかしこれはソートされた結果を返さないことに注意してください。その場合は、目的の軸に沿ってnp.argsort()を使用できます。

indices = np.argsort(arr, axis=1)[:, -N:]

# Result
x = arr.shape[0]
arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N)

これが一例です。

In [42]: a = np.random.randint(0, 20, (10, 10))

In [44]: a
Out[44]:
array([[ 7, 11, 12,  0,  2,  3,  4, 10,  6, 10],
       [16, 16,  4,  3, 18,  5, 10,  4, 14,  9],
       [ 2,  9, 15, 12, 18,  3, 13, 11,  5, 10],
       [14,  0,  9, 11,  1,  4,  9, 19, 18, 12],
       [ 0, 10,  5, 15,  9, 18,  5,  2, 16, 19],
       [14, 19,  3, 11, 13, 11, 13, 11,  1, 14],
       [ 7, 15, 18,  6,  5, 13,  1,  7,  9, 19],
       [11, 17, 11, 16, 14,  3, 16,  1, 12, 19],
       [ 2,  4, 14,  8,  6,  9, 14,  9,  1,  5],
       [ 1, 10, 15,  0,  1,  9, 18,  2,  2, 12]])

In [45]: np.argpartition(a, np.argmin(a, axis=0))[:, 1:] # 1 is because the first item is the minimum one.
Out[45]:
array([[4, 5, 6, 8, 0, 7, 9, 1, 2],
       [2, 7, 5, 9, 6, 8, 1, 0, 4],
       [5, 8, 1, 9, 7, 3, 6, 2, 4],
       [4, 5, 2, 6, 3, 9, 0, 8, 7],
       [7, 2, 6, 4, 1, 3, 8, 5, 9],
       [2, 3, 5, 7, 6, 4, 0, 9, 1],
       [4, 3, 0, 7, 8, 5, 1, 2, 9],
       [5, 2, 0, 8, 4, 6, 3, 1, 9],
       [0, 1, 9, 4, 3, 7, 5, 2, 6],
       [0, 4, 7, 8, 5, 1, 9, 2, 6]])

In [46]: np.argpartition(a, np.argmin(a, axis=0))[:, -3:]
Out[46]:
array([[9, 1, 2],
       [1, 0, 4],
       [6, 2, 4],
       [0, 8, 7],
       [8, 5, 9],
       [0, 9, 1],
       [1, 2, 9],
       [3, 1, 9],
       [5, 2, 6],
       [9, 2, 6]])

In [89]: a[np.repeat(np.arange(x), 3), ind.ravel()].reshape(x, 3)
Out[89]:
array([[10, 11, 12],
       [16, 16, 18],
       [13, 15, 18],
       [14, 18, 19],
       [16, 18, 19],
       [14, 14, 19],
       [15, 18, 19],
       [16, 17, 19],
       [ 9, 14, 14],
       [12, 15, 18]])
7
Kasrâmvd

元の配列のサイズと選択したサイズによっては、これはフルソートよりも速くなります。

>>> A = np.random.randint(0,10,10)
>>> A
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 0])
>>> B = np.zeros(3, int)
>>> for i in xrange(3):
...     idx = np.argmax(A)
...     B[i]=idx; A[idx]=0 #something smaller than A.min()
...     
>>> B
array([0, 2, 3])

もちろん、元の配列を改ざんする必要があります。これをコピーするか、元の値に戻すことで(必要に応じて)修正できます。 ...どちらの方があなたのユースケースに対してより安いです。

4
Paul

bottleneck は、N個の最大値を得るためだけに配列全体をソートする費用が大きすぎる場合、部分的なソート機能を持ちます。

私はこのモジュールについて何も知りません。 numpy partial sortとグーグルしました。

3
Katriel

つかいます:

def max_indices(arr, k):
    '''
    Returns the indices of the k first largest elements of arr
    (in descending order in values)
    '''
    assert k <= arr.size, 'k should be smaller or equal to the array size'
    arr_ = arr.astype(float)  # make a copy of arr
    max_idxs = []
    for _ in range(k):
        max_element = np.max(arr_)
        if np.isinf(max_element):
            break
        else:
            idx = np.where(arr_ == max_element)
        max_idxs.append(idx)
        arr_[idx] = -np.inf
    return max_idxs

2D配列でも動作します。例えば、

In [0]: A = np.array([[ 0.51845014,  0.72528114],
                     [ 0.88421561,  0.18798661],
                     [ 0.89832036,  0.19448609],
                     [ 0.89832036,  0.19448609]])
In [1]: max_indices(A, 8)
Out[1]:
    [(array([2, 3], dtype=int64), array([0, 0], dtype=int64)),
     (array([1], dtype=int64), array([0], dtype=int64)),
     (array([0], dtype=int64), array([1], dtype=int64)),
     (array([0], dtype=int64), array([0], dtype=int64)),
     (array([2, 3], dtype=int64), array([1, 1], dtype=int64)),
     (array([1], dtype=int64), array([1], dtype=int64))]

In [2]: A[max_indices(A, 8)[0]][0]
Out[2]: array([ 0.89832036])
2
AndyK

つかいます:

from operator import itemgetter
from heapq import nlargest
result = nlargest(N, enumerate(your_list), itemgetter(1))

これでresultリストは _ n _ tuples(indexvalue)を含み、ここでvalueは最大化されます。

2
off99555

メソッドnp.argpartitionは、最大のk個のインデックスのみを返し、ローカルソートを実行します。arrayが非常に大きい場合、np.argsort(フルソートを実行する)より高速です。しかし、返されるインデックスは昇順/降順の NOT です。例を挙げましょう。

Enter image description here

厳密な昇順の上位kインデックスが必要な場合、np.argpartitionは必要なものを返さないことがわかります。

Np.argpartitionの後に手作業でソートを行うのとは別に、私の解決策はPyTorch、 torch.topk 、ニューラルネットワーク構築のためのツールを使うことです。 MKLを使用するとNumPyと同じくらい高速で、大量の行列/ベクトル計算が必要な場合はGPUを向上させることができます。

厳密な昇順トップkインデックスコードは次のようになります。

Enter image description here

torch.topk はトーチテンソルを受け入れ、torch.Tensor型の上位kの値と上位kのインデックスの両方を返します。 npと同様に、torch.topkもaxis引数を受け入れて、多次元配列/テンソルを扱うことができます。

2
futureer

以下は、最大要素とその位置を確認するための非常に簡単な方法です。ここでaxisはドメインです。 2Dの場合、axis = 0は列方向の最大数、axis = 1は行方向の最大数を意味します。そしてより高い次元のためにそれはあなた次第です。

M = np.random.random((3, 4))
print(M)
print(M.max(axis=1), M.argmax(axis=1))
1
liberal

私はnp.uniqueを使うのが最も直感的だとわかりました。

その考え方は、uniqueメソッドが入力値のインデックスを返すということです。そして、最大の固有値と指標から、元の値の位置を再現することができます。

multi_max = [1,1,2,2,4,0,0,4]
uniques, idx = np.unique(multi_max, return_inverse=True)
print np.squeeze(np.argwhere(idx == np.argmax(uniques)))
>> [4 7]
0
phi

他の人々が言っ​​たように、最も時間効率の良い方法は手動で配列を反復してkサイズの最小ヒープを保つことだと思います。

そして私はまた、ブルートフォースアプローチを思いつきました:

top_k_index_list = [ ]
for i in range(k):
    top_k_index_list.append(np.argmax(my_array))
    my_array[top_k_index_list[-1]] = -float('inf')

Argmaxを使用してそのインデックスを取得したら、最大の要素を大きな負の値に設定します。そして、次にargmaxを呼び出すと、2番目に大きい要素が返されます。そして、あなたはこれらの要素の元の値を記録してあなたが望むならそれらを回復することができます。

0
Zhenghao Zhao