问题:如何获取NumPy数组中N个最大值的索引?
NumPy提出了一种通过来获取数组最大值的索引的方法np.argmax
。
我想要类似的事情,但是返回N
最大值的索引。
例如,如果我有一个数组,[1, 3, 2, 4, 5]
,function(array, n=3)
将返回的索引[4, 3, 1]
相对应的元素[5, 4, 3]
。
回答 0
我想出的最简单的方法是:
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
提供了一种进行部分排序的内置方法。到目前为止,我还没有找到一个。
回答 1
较新的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)时间。
回答 2
更简单了:
idx = (-arr).argsort()[:n]
其中,n是最大值的数量。
回答 3
采用:
>>> 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 —堆队列算法
回答 4
如果碰巧正在使用多维数组,则需要展平和分解索引:
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])
回答 5
如果您不在乎可以使用的第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
了。
回答 6
对于多维数组,可以使用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
这将比完整排序要快,具体取决于原始数组的大小和所选内容的大小:
>>> 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])
当然,它涉及篡改原始阵列。您可以通过复制或替换原始值来解决(如果需要)的问题。…以您的使用案例中较便宜的价格为准
回答 8
方法np.argpartition
仅返回k个最大的索引,执行局部排序,并且比np.argsort
数组很大时要快(执行完整排序)。但是返回的索引不是按升序/降序排列的。让我们举一个例子:
我们可以看到,如果您要对前k个索引使用严格的升序,np.argpartition
则不会返回您想要的结果。
除了在np.argpartition之后手动进行排序之外,我的解决方案是使用PyTorch(torch.topk
一种用于神经网络构建的工具),为类似NumPy的API提供CPU和GPU支持。它与带有MKL的NumPy一样快,并且如果需要大型矩阵/矢量计算,则可以提供GPU增强。
严格的上升/下降前k个索引代码将是:
请注意,它torch.topk
接受火炬张量,并返回type中的前k个值和前k个索引torch.Tensor
。与np相似,torch.topk也接受轴参数,以便您可以处理多维数组/张量。
回答 9
采用:
from operator import itemgetter
from heapq import nlargest
result = nlargest(N, enumerate(your_list), itemgetter(1))
现在,result
列表将包含N个元组(index
,value
),其中value
已最大化。
回答 10
采用:
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])
回答 11
bottleneck
如果仅为了获得N个最大值而对整个数组进行排序的开销太大,则具有部分排序函数。
我对这个模块一无所知。我只是谷歌搜索numpy partial sort
。
回答 12
以下是查看最大元素及其位置的非常简单的方法。这axis
是域;axis
= 0表示按列最大数量,而axis
1表示2D情况下按行最大数量。对于更大的尺寸,则取决于您。
M = np.random.random((3, 4))
print(M)
print(M.max(axis=1), M.argmax(axis=1))
回答 13
我发现使用起来最直观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]
回答 14
我认为,最省时的方法是手动遍历数组,并保持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将返回第二大元素。您可以记录这些元素的原始值,并根据需要恢复它们。
回答 15
这段代码适用于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个元素