IT

NumPy 어레이에서 N개의 최대값 인덱스를 가져오려면 어떻게 해야 합니까?

itgroup 2023. 1. 1. 11:10
반응형

NumPy 어레이에서 N개의 최대값 인덱스를 가져오려면 어떻게 해야 합니까?

NumPy는 를 통해 배열의 최대값 인덱스를 가져오는 방법을 제안합니다.

저도 비슷한 것을 원합니다만, 그 인덱스를 돌려드립니다.N최대값

들어 「」는 「」입니다.[1, 3, 2, 4, 5] , , , 「 」nargmax(array, n=3)됩니다.[4, 3, 1]에 하는 것[5, 4, 3].

새로운 NumPy 버전(1.8 이상)에는 이러한 기능이 있습니다.가장 큰 네 가지 원소의 지수를 얻으려면

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

>>> top4 = a[ind]
>>> top4
array([4, 9, 6, 9])

와 달리 이 함수는 최악의 경우 선형 시간에 실행되지만 반환된 인덱스는 평가 결과에서 알 수 있듯이 정렬되지 않습니다.a[ind]필요한 경우 나중에 정렬합니다.

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

이렇게 정렬된 순서대로 상위k 요소를 가져오려면 O(n + k log k) 시간이 걸립니다.

내가 생각해낸 것 중 가장 간단한 건

>>> import numpy as np
>>> arr = np.array([1, 3, 2, 4, 5])
>>> arr.argsort()[-3:][::-1]
array([4, 3, 1])

여기에는 어레이의 완전한 종류가 포함됩니다.numpy부분적인 정렬을 할 수 있는 빌트인 방법을 제공합니다.지금까지 찾을 수 없었습니다.

작은 )nCython에서 코드화하는 것을 검토해 볼 가치가 있을지도 모릅니다.

심플하고 심플하게:

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]

일반 Python 목록의 경우:

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

2를 Python 2를 합니다.xrangerange.

출처: 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번째로 큰 요소의 순서를 신경 쓰지 않으면 전체 정렬보다 성능이 우수합니다.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])

이 질문에는 크레딧이 들어갑니다.

, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.argpartition 능가하다argsort의의의 의의 의의 의의의 의의의의의 。

코딩의 용이성과 속도를 비교한 세 가지 답변

속도는 나의 요구에 중요했기 때문에 나는 이 질문에 대한 세 가지 답을 테스트했다.

이 세 가지 답변 중 코드는 제 특정 사례에 맞게 수정되었습니다.

그리고 각 방법의 속도를 비교했습니다.

코딩 기능:

  1. NPE의 답변은 그 다음으로 우아하고 제 요구에 맞는 속도였습니다.
  2. Fred Foos의 답변은 제 요구에 가장 많은 리팩터링이 필요했지만 가장 빨랐습니다.더 많은 작업이 필요했지만 나쁘지 않았고 속도 면에서 상당한 이점이 있었기 때문에 이 답변을 선택했습니다.
  3. off 99555의 답변이 가장 우아했지만 가장 느렸다.

테스트와 비교를 위한 완전한 코드

import numpy as np
import time
import random
import sys
from operator import itemgetter
from heapq import nlargest

''' Fake Data Setup '''
a1 = list(range(1000000))
random.shuffle(a1)
a1 = np.array(a1)

''' ################################################ '''
''' NPE's Answer Modified A Bit For My Case '''
t0 = time.time()
indices = np.flip(np.argsort(a1))[:5]
results = []
for index in indices:
    results.append((index, a1[index]))
t1 = time.time()
print("NPE's Answer:")
print(results)
print(t1 - t0)
print()

''' Fred Foos Answer Modified A Bit For My Case'''
t0 = time.time()
indices = np.argpartition(a1, -6)[-5:]
results = []
for index in indices:
    results.append((a1[index], index))
results.sort(reverse=True)
results = [(b, a) for a, b in results]
t1 = time.time()
print("Fred Foo's Answer:")
print(results)
print(t1 - t0)
print()

''' off99555's Answer - No Modification Needed For My Needs '''
t0 = time.time()
result = nlargest(5, enumerate(a1), itemgetter(1))
t1 = time.time()
print("off99555's Answer:")
print(result)
print(t1 - t0)

속도 보고서를 사용한 출력

NPE의 답변:

[(631934, 999999), (788104, 999998), (413003, 999997), (536514, 999996), (81029, 999995)]
0.1349949836730957

Fred Foo의 답변:

[(631934, 999999), (788104, 999998), (413003, 999997), (536514, 999996), (81029, 999995)]
0.011161565780639648

off 99555의 답변:

[(631934, 999999), (788104, 999998), (413003, 999997), (536514, 999996), (81029, 999995)]
0.439760684967041

의 경우 '다차원 배열'을할 수 .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.argpartition는 가장 정렬을 하며, "K"보다 .np.argsort(전체 정렬 수행 중) 배열이 상당히 큰 경우.그러나 반환된 인덱스는 오름차순/내림차순이 아닙니다.예를 들면 다음과 같습니다.

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

인덱스를 로 하는 , 「」k」를 할 수 .np.argpartition원하는 걸 돌려주지 않을 거야

np.argpartition 후에 수동으로 정렬하는 것 외에 NumPy와 같은 API를 CPU와 GPU를 모두 지원하는 뉴럴 네트워크 구축 툴인 PyTorch를 사용하는 것이 제 해결책입니다.MKL을 사용한 NumPy만큼 고속이며, 대규모 매트릭스/벡터 계산이 필요한 경우 GPU를 확장할 수 있습니다.

엄밀한 상승/하강 상위 k개의 인덱스 코드는 다음과 같습니다.

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

는 토치 텐서를 받아들이고 type의 top k 값과 top k 인덱스를 모두 반환합니다.torch.Tensor로 torch 배열.np을 할 수 축

이것은, 원래의 어레이의 사이즈와 선택되고 있는 사이즈에 따라서는, 풀 정렬보다 빠릅니다.

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

물론 원래 어레이를 조작해야 합니다.복사 또는 원래 값 치환으로 수정할 수 있습니다(필요한 경우...어느 쪽이 더 저렴한지 확인하실 수 있습니다.

용도:

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

다음은 최대 요소 및 위치를 매우 쉽게 확인할 수 있는 방법입니다.서 ★★★★axisaxis하고 = 0은 열의 최대 수를 의미합니다.axis= 1 2 2D 사d 、 2D 사 1d 。그리고 더 높은 차원에 대해서는 당신에게 달려 있습니다.

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

n번째 값에 동점이 있을 경우 n이 증가하는 더 복잡한 방법을 다음에 나타냅니다.

>>>> def get_top_n_plus_ties(arr,n):
>>>>     sorted_args = np.argsort(-arr)
>>>>     thresh = arr[sorted_args[n]]
>>>>     n_ = np.sum(arr >= thresh)
>>>>     return sorted_args[:n_]
>>>> get_top_n_plus_ties(np.array([2,9,8,3,0,2,8,3,1,9,5]),3)
array([1, 9, 2, 6])

가장 직관적으로 사용할 수 있습니다.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]

가장 시간 효율이 높은 방법은 어레이를 수동으로 반복하고 다른 사람들이 언급한 것처럼 최소 크기의 최소 히프를 유지하는 것이라고 생각합니다.

그리고 난 무차별적인 접근법도 생각해냈어.

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를 호출하면 두 번째로 큰 요소가 반환됩니다.또한 이러한 요소의 원래 값을 기록하고 필요에 따라 복구할 수 있습니다.

이 코드는 Numpy 2D 매트릭스 어레이에서 작동합니다.

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_mough 요소를 추출하기 위해 작동하는 true-false n_mough 매트릭스 인덱싱이 생성됩니다.

top_k < < axis _ length top 、 argsort arg arg arg arg arg arg arg arg arg arg arg arg

import numpy as np

def get_sorted_top_k(array, top_k=1, axis=-1, reverse=False):
    if reverse:
        axis_length = array.shape[axis]
        partition_index = np.take(np.argpartition(array, kth=-top_k, axis=axis),
                                  range(axis_length - top_k, axis_length), axis)
    else:
        partition_index = np.take(np.argpartition(array, kth=top_k, axis=axis), range(0, top_k), axis)
    top_scores = np.take_along_axis(array, partition_index, axis)
    # resort partition
    sorted_index = np.argsort(top_scores, axis=axis)
    if reverse:
        sorted_index = np.flip(sorted_index, axis=axis)
    top_sorted_scores = np.take_along_axis(top_scores, sorted_index, axis)
    top_sorted_indexes = np.take_along_axis(partition_index, sorted_index, axis)
    return top_sorted_scores, top_sorted_indexes

if __name__ == "__main__":
    import time
    from sklearn.metrics.pairwise import cosine_similarity

    x = np.random.rand(10, 128)
    y = np.random.rand(1000000, 128)
    z = cosine_similarity(x, y)
    start_time = time.time()
    sorted_index_1 = get_sorted_top_k(z, top_k=3, axis=1, reverse=True)[1]
    print(time.time() - start_time)

사전을 사용하여 numpy 배열에서 상위 k개의 값과 인덱스를 찾을 수 있습니다.예를 들어, 상위 2개의 최대값과 인덱스를 찾는 경우

import numpy as np
nums = np.array([0.2, 0.3, 0.25, 0.15, 0.1])


def TopK(x, k):
    a = dict([(i, j) for i, j in enumerate(x)])
    sorted_a = dict(sorted(a.items(), key = lambda kv:kv[1], reverse=True))
    indices = list(sorted_a.keys())[:k]
    values = list(sorted_a.values())[:k]
    return (indices, values)

print(f"Indices: {TopK(nums, k = 2)[0]}")
print(f"Values: {TopK(nums, k = 2)[1]}")


Indices: [1, 2]
Values: [0.3, 0.25]

argpartition을 사용한 벡터화된 2D 구현:

k = 3
probas = np.array([
    [.6, .1, .15, .15],
    [.1, .6, .15, .15],
    [.3, .1, .6, 0],
])

k_indices = np.argpartition(-probas, k-1, axis=-1)[:, :k]

# adjust indices to apply in flat array
adjuster = np.arange(probas.shape[0]) * probas.shape[1]
adjuster = np.broadcast_to(adjuster[:, None], k_indices.shape)
k_indices_flat = k_indices + adjuster

k_values = probas.flatten()[k_indices_flat]

# k_indices:
# array([[0, 2, 3],
#        [1, 2, 3],
#        [2, 0, 1]])
# k_values:
# array([[0.6 , 0.15, 0.15],
#        [0.6 , 0.15, 0.15],
#       [0.6 , 0.3 , 0.1 ]])

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

반응형