How do I get indices of N maximum values in a NumPy array?
numpy提出了一种通过
我想要一个类似的东西,但是返回
例如,如果我有一个数组,
新的numpy版本(1.8及更高版本)有一个称为
1 2 3 4 5 6 7 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]) >>> a[ind] array([4, 9, 6, 9]) |
与
1 2 | >>> ind[np.argsort(a[ind])] array([1, 8, 5, 0]) |
。
以这种方式获得排序顺序的前k个元素需要O(n+k logk)时间。
我能想到的最简单的方法是:
1 2 3 4 5 6 | 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]) |
这涉及到一种完整的数组。我想知道
如果这个解决方案的速度太慢(特别是对于小的
更简单:
1 | idx = (-arr).argsort()[:n] |
。
其中n是最大值的数目。
用途:
1 2 3 4 5 | >>> import heapq >>> import numpy >>> a = numpy.array([1, 3, 2, 4, 5]) >>> heapq.nlargest(3, range(len(a)), a.take) [4, 3, 1] |
对于常规的python列表:
1 2 3 | >>> a = [1, 3, 2, 4, 5] >>> heapq.nlargest(3, range(len(a)), a.__getitem__) [4, 3, 1] |
。
如果使用python 2,请使用
来源:heapq-堆队列算法
如果您碰巧使用多维数组,那么您将需要展平并展开索引:
1 2 3 4 5 6 | 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) |
例如:
1 2 3 4 5 6 7 8 9 | >>> 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个最大元素的顺序,可以使用
1 2 3 4 | 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值增加的情况下,
对于多维数组,可以使用
1 2 | # For a 2D array indices = np.argpartition(arr, -N, axis=1)[:, -N:] |
号
抓取物品:
1 2 | x = arr.shape[0] arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N) |
号
但请注意,这不会返回已排序的结果。在这种情况下,您可以沿预期轴使用
1 2 3 4 5 | indices = np.argsort(arr, axis=1)[:, -N:] # Result x = arr.shape[0] arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N) |
号
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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]]) |
号
这将比完全排序更快,具体取决于原始数组的大小和所选内容的大小:
1 2 3 4 5 6 7 8 9 10 | >>> 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]) |
号
当然,它涉及篡改原始数组。您可以通过复制或替换原始值来修复(如果需要)。…以您的用例便宜的为准。
如果仅仅为了得到n个最大值而对整个数组进行排序的开销太大,那么
我对这个模块一无所知;我只是在google上搜索
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
号
它也适用于二维阵列。例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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]) |
号
方法
。
我们可以看到,如果你想要一个严格的K指数升序,那么
除了在np.argpartition之后手动排序之外,我的解决方案是使用pytorch,
严格的上升/下降顶部K索引代码将是:
氧化镁
注意,
用途:
1 2 3 | from operator import itemgetter from heapq import nlargest result = nlargest(N, enumerate(your_list), itemgetter(1)) |
现在,
下面是一个很容易看到最大元素及其位置的方法。这里,
1 2 3 | M = np.random.random((3, 4)) print(M) print(M.max(axis=1), M.argmax(axis=1)) |
号
我认为最省时的方法是手动遍历数组并保留k大小的最小堆,正如其他人提到的那样。
我还想出了一个蛮力的方法:
1 2 3 4 | 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的下一个调用将返回第二大元素。您可以记录这些元素的原始值并在需要时恢复它们。
我发现使用
其思想是,unique方法返回输入值的索引。然后根据最大唯一值和指标,重新创建原始值的位置。
1 2 3 4 | 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] |
号