Programing

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

lottogame 2020. 2. 21. 22:04
반응형

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


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

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

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


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

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


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


더 간단하면서도 :

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

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


사용하다:

>>> 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 — 힙 큐 알고리즘


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

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

사용할 수 있는 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납니다.


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

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

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

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


메서드 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는 축 인수를 허용하므로 다차원 배열 / 텐서를 처리 할 수 ​​있습니다.


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

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


사용하다:

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

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


사용하다:

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

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

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

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

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

참고 URL : https://stackoverflow.com/questions/6910641/how-do-i-get-indices-of-n-maximum-values-in-a-numpy-array



반응형