NumPy 배열에서 N 최대 값의 인덱스를 어떻게 얻습니까?


482

NumPy는 다음을 통해 배열의 최대 값 인덱스를 얻는 방법을 제안합니다. np.argmax .

비슷한 것을 원하지만 N최대 값 의 색인을 반환 합니다.

I 배열이있는 경우 예를 들어 [1, 3, 2, 4, 5], function(array, n=3)인덱스 반환 [4, 3, 1]요소에 대응 [5, 4, 3].



4
귀하의 질문은 실제로 잘 정의되어 있지 않습니다. 예를 들어, 지수 (예상) 무엇을 할 수 것 array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5]), 엉 n= 3? 모두의 어느 하나의 대안은, 같은 [0, 2, 3], [0, 2, 9], ...올바른 것입니까? 특정 요구 사항에 대해 자세히 설명하십시오. 덕분에
먹는

@eat, 나는이 특정 경우에 반환 될 것으로 신경 쓰지 않습니다. 처음 발생한 것을 반환하는 것이 논리적 인 것처럼 보이지만 그것은 나에게 요구되는 것은 아닙니다.
Alexis Métaireau

argsort반환 된 indeces의 순서에 신경 쓰지 않으면 실행 가능한 대안이 될 수 있습니다. 아래 답변을 참조하십시오.
Blue

답변:


347

내가 생각해 낸 가장 간단한 방법은 다음과 같습니다.

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 에서 코드를 작성하는 것이 좋습니다.


1
행 3을 arr.argsort()[-1:-4:-1]? 와 같이 쓸 수 있습니까? 나는 인터프리터에서 그것을 시도했지만 동일한 결과를 얻지 만 몇 가지 예에 의해 깨지지 않았는지 궁금합니다.
abroekhof

44
@abroekhof 예, 목록 또는 배열과 동일해야합니다. 대안으로, 이것은 np.argsort(-arr)[:3]더 읽기 쉽고 포인트를 사용하여 반전하지 않고 수행 할 수 있습니다 .
askewchan

6
[::-1]은 무슨 뜻인가요? @NPE
1a1a11a

@ 1a1a11a 그것은 배열을 뒤집는 것을 의미합니다 (문자 그대로, 제한되지 않은 최소값에서 역순으로 제한되지 않은 최대 값으로 배열의 사본을 가져옵니다)
FizBack

15
arr.argsort()[::-1][:n]n=0전체 배열 대신 빈 값을 반환하기 때문에 더 좋습니다
abora

599

최신 NumPy 버전 (1.8 이상)에는이를 argpartition위한 함수가 있습니다 . 네 가지 가장 큰 요소의 지수를 얻으려면

>>> 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 ) 시간이 걸립니다.


27
@varela argpartitionintroselect 알고리즘을 사용하여 선형 시간 O (n)으로 실행됩니다 . 후속 정렬은 k 개의 요소 만 처리하므로 O (k log k)로 실행됩니다.
프레드 푸

2
누군가 정확히 np.argpartition그리고 그것의 자매 알고리즘이 어떻게 np.partition작동 하는지 궁금하다면 링크 된 질문에보다 자세한 설명이 있습니다 : stackoverflow.com/questions/10337533/…
Ramon Martinez

7
@FredFoo : 왜 -4를 사용 했습니까? 당신은 거꾸로 시작하기 위해 그렇게 했습니까? (k는 긍정적이거나 부정적인 것이므로 저에게도 동일하게 작용합니다! 가장 작은 숫자 만 먼저 인쇄합니다!
Rika

2
@LKT는 a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])일반적인 파이썬리스트가리스트에 의한 색인 생성을 지원하지 않기 때문에 사용합니다np.array
Marawan Okasha

2
@Umangsinghal np.argpartition은 선택적 axis인수를 취합니다 . 각 행에 대한 상위 n 값의 인덱스를 찾으려면 다음과 같이하십시오.np.argpartition(a, -n, axis=1)[-n:]
Ralph

48

더 간단하면서도 :

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

여기서 n 은 최대 값 수입니다.


7
2D 배열 에서이 작업을 수행 할 수 있습니까? 그렇지 않다면 아마도 어떻게 알 수 있습니까?
앤드류 헌트

2
@AndrewHundt는 : 단지 (-arr) .argsort (축선 = -1) [N :,] 사용
MiniQuark

2
비슷한 방법으로 arr[arr.argsort()[-n:]]배열을 부정하는 대신 마지막 n 개의 요소를
취하십시오

35

사용하다:

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

일반 파이썬 목록의 경우 :

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

Python 2를 사용 xrange하는 경우 대신range .

출처 : heapq — 힙 큐 알고리즘


2
여기에 루프가 전혀 필요하지 않습니다 heapq.nlargest(3, xrange(len(a)), a.take). 파이썬리스트의 경우 .__getitem__대신 사용할 수 있습니다 .take.
Ashwini Chaudhary

n 차원 배열의 경우 A: heapq.nlargest(3, range(len(A.ravel())), A.ravel().take). (이것이 뷰에서만 작동하기를 바랍니다. ( ravel vs flatten] ( stackoverflow.com/a/28930580/603003 ) 참조)
ComFreek

31

다차원 배열로 작업하는 경우 인덱스를 평평하게하고 풀어야합니다.

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])

9

사용할 수 있는 K 번째로 큰 요소 의 순서 에 신경 쓰지 않으면 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의 값이 증가함에 따라 argpartition성능이 뛰어 argsort납니다.


7

다차원 배열의 경우 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]])

나는 np.take_along_axis(이 질문에 대답했을 때 존재하지 않았을 수도 있음)을 사용하여 색인 작성을 단순화 할 수 있다고 생각합니다.
Eric

4

이것은 원래 배열의 크기와 선택 크기에 따라 전체 정렬보다 빠릅니다.

>>> 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])

물론 원래 배열을 변경하는 것도 포함됩니다. 사본을 만들거나 원래 값을 다시 대체하여 필요한 경우 수정할 수 있습니다. ... 사용 사례에 비해 저렴합니다.


FWIW, 귀하의 솔루션은 모든 상황에서 명확한 솔루션을 제공하지는 않습니다. OP는 이러한 모호하지 않은 사례를 처리하는 방법을 설명해야합니다. 덕분에
먹는

@eat OP의 질문은 조금 모호합니다. 그러나 구현이 실제로 해석에 개방되지는 않습니다. :) OP는 이 특정 솔루션이 요구 사항을 충족하는지 확인하기 위해 np.argmax docs.scipy.org/doc/numpy/reference/generated/numpy.argmax.html 의 정의를 참조해야 합니다. OP의 언급 된 reqirement를 충족하는 모든 솔루션이 허용 될 수 있습니다.
Paul

글쎄, 구현 argmax(.)도 모호하지 않은 것으로 간주 할 수 있습니다. (IMHO는 일종의 단락 논리를 따르려고하지만 불행히도 보편적으로 수용 가능한 행동을 제공하지 못합니다). 감사합니다
먹습니다

3

메서드 np.argpartition는 k 개의 가장 큰 인덱스 만 반환하고, 로컬 정렬을 수행하며, np.argsort배열이 상당히 클 때 (전체 정렬 수행) 보다 빠릅니다 . 그러나 반환 된 지수는 오름차순 / 내림차순아닙니다 . 예를 들어 봅시다 :

여기에 이미지 설명을 입력하십시오

우리는 엄격한 오름차순 주문 k 지수 np.argpartition를 원한다면 원하는 것을 반환하지 않을 것임을 알 수 있습니다.

np.argpartition 이후에 수동으로 정렬하는 것 외에도, 내 솔루션은 torch.topk신경 네트워크 구성을위한 도구 인 PyTorch를 사용 하여 NumPy와 유사한 API를 CPU와 GPU를 지원하는 것입니다. MKL을 사용하면 NumPy만큼 빠르며 큰 행렬 / 벡터 계산이 필요한 경우 GPU를 향상시킵니다.

엄격한 오름차순 / 내림차순 k 지수 코드는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

torch.topk토치 텐서 를 받아들이고 top k 값과 top k 인덱스를 모두 type으로 반환합니다 torch.Tensor. np와 마찬가지로 torch.topk는 축 인수를 허용하므로 다차원 배열 / 텐서를 처리 할 수 ​​있습니다.


2

사용하다:

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

이제 result목록에는 최대화 된 N 개의 튜플 ( index, value) 이 포함 value됩니다.


2

사용하다:

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])

잘 작동하지만 배열 A에 중복 (최대) 값이 있으면 더 많은 결과를 제공합니다. 정확히 k 개의 결과를 기대하지만 중복 값의 경우 k 개 이상의 결과를 얻습니다.
귀도

코드를 약간 수정했습니다. 반환되는 인덱스 목록의 길이는 정확히 k와 같습니다. 중복이 있으면 단일 튜플로 그룹화됩니다.
X Æ A-12

1

bottleneck N 개의 가장 큰 값을 얻기 위해 전체 배열을 정렬하는 비용이 너무 큰 경우 부분 정렬 기능이 있습니다.

나는이 모듈에 대해 아무것도 모른다; 방금 봤어요 numpy partial sort.


병목 현상에는 부분 정렬 기능이없고 파티션 기능도 있지만 정렬되지 않습니다
nbecker

1

다음은 최대 요소와 위치를 볼 수있는 매우 쉬운 방법입니다. axis도메인은 다음과 같습니다 . axis= 0은 열 단위 최대 수를 axis의미 하고 = 1은 2D 경우 행 최대 수를 의미합니다. 그리고 더 큰 치수의 경우 그것은 당신에게 달려 있습니다.

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


0

가장 직관적 인 사용을 발견했습니다 np.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

다른 사람들이 언급했듯이 가장 시간 효율적인 방법은 수동으로 배열을 반복하고 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 호출은 두 번째로 큰 요소를 반환합니다. 또한 이러한 요소의 원래 값을 기록하고 원하는 경우 복구 할 수 있습니다.


0

이 코드는 numpy 행렬 배열에서 작동합니다.

mat = np.array([[1, 3], [2, 5]]) # numpy matrix

n = 2  # n
n_largest_mat = np.sort(mat, axis=None)[-n:] # n_largest 
tf_n_largest = np.zeros((2,2), dtype=bool) # all false matrix
for x in n_largest_mat: 
  tf_n_largest = (tf_n_largest) | (mat == x) # true-false  

n_largest_elems = mat[tf_n_largest] # true-false indexing 

이것은 행렬 배열에서 n_largest 요소를 추출하는 실제 거짓 n_largest 매트릭스 인덱싱을 생성합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.