是否可以按降序使用argsort

时间:2013-05-10 15:57:47

标签: python numpy

请考虑以下代码:

avgDists = np.array([1, 8, 6, 9, 4])
ids = avgDists.argsort()[:n]

这给了我n个最小元素的索引。是否可以按降序使用相同的argsort来获取n最高元素的索引?

10 个答案:

答案 0 :(得分:165)

如果否定数组,则最低元素成为最高元素,反之亦然。因此,n最高元素的索引是:

(-avgDists).argsort()[:n]

comments中所述,另一种推理此问题的方法是观察argsort中的大元素 last 。因此,您可以从argsort的尾部读取以找到n最高元素:

avgDists.argsort()[::-1][:n]

这两种方法在时间复杂度上都是 O(n log n),因为argsort调用是这里的主导术语。但第二种方法有一个很好的优点:它用 O(1)切片取代了 O(n)对数组的否定。如果您正在循环中使用小数组,那么您可以通过避免这种否定获得一些性能提升,如果您正在使用大型数组,那么您可以节省内存使用量,因为否定会创建一个副本整个阵列。

请注意,这些方法并不总是提供相同的结果:如果向argsort请求稳定的排序实现,例如通过传递关键字参数kind='mergesort',第一个策略将保持排序稳定性,但第二个策略将破坏稳定性(即相等项的位置将被反转)。

答案 1 :(得分:65)

就像Python一样,[::-1]反转argsort()返回的数组,[:n]给出最后n个元素:

>>> avgDists=np.array([1, 8, 6, 9, 4])
>>> n=3
>>> ids = avgDists.argsort()[::-1][:n]
>>> ids
array([3, 1, 2])

此方法的优点是ids是avgDists的view

>>> ids.flags
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

('OWNDATA'为False表示这是一个视图,而不是副本)

另一种方法是:

(-avgDists).argsort()[:n]

问题在于它的工作方式是在数组中创建每个元素的负数:

>>> (-avgDists)
array([-1, -8, -6, -9, -4])

ANd创建了一个副本:

>>> (-avgDists_n).flags['OWNDATA']
True

所以如果你给每个人计时,即使是这个非常小的数据集:

>>> import timeit
>>> timeit.timeit('(-avgDists).argsort()[:3]', setup="from __main__ import avgDists")
4.2879798610229045
>>> timeit.timeit('avgDists.argsort()[::-1][:3]', setup="from __main__ import avgDists")
2.8372560259886086

视图方法快得多

答案 2 :(得分:6)

您可以使用翻转命令numpy.flipud()numpy.fliplr()在使用argsort命令排序后按降序获取索引。这就是我通常做的事情。

答案 3 :(得分:4)

如果您只需要最低/最高n个元素的索引,而不是使用np.argsort,您可以使用np.argpartition

这并不需要对整个阵列进行排序,只需要对您需要的部分进行排序,但请注意分区内的"顺序"是未定义的,所以虽然它给出了正确的索引,但它们可能没有正确排序:

>>> avgDists = [1, 8, 6, 9, 4]
>>> np.array(avgDists).argpartition(2)[:2]  # indices of lowest 2 items
array([0, 4], dtype=int64)

>>> np.array(avgDists).argpartition(-2)[-2:]  # indices of highest 2 items
array([1, 3], dtype=int64)

答案 4 :(得分:2)

您可以创建数组的副本,然后将每个元素乘以-1 作为一种效果,最大的元素将变得最小。
副本中n个最小元素的indeces是原始元素中最大的元素。

答案 5 :(得分:1)

用你的例子:

avgDists = np.array([1, 8, 6, 9, 4])

获取n个最大值的索引:

ids = np.argpartition(avgDists, -n)[-n:]

按降序排序:

ids = ids[np.argsort(avgDists[ids])[::-1]]

获得结果(n = 4):

>>> avgDists[ids]
array([9, 8, 6, 4])

答案 6 :(得分:1)

正如@Kanmani所暗示的,可以使用numpy.flip来简化实现,如下所示:

import numpy as np

avgDists = np.array([1, 8, 6, 9, 4])
ids = np.flip(np.argsort(avgDists))
print(ids)

通过使用访问者模式而不是成员函数,可以更轻松地读取操作顺序。

答案 7 :(得分:0)

另一种方法是在argsort的参数中只使用' - ',如下所示:“df [np.argsort(-df [:,0])]”,前提是df是数据帧,你想对它进行排序由第一列(由列号'0'表示)。根据需要更改列名称。当然,该列必须是数字列。

答案 8 :(得分:0)

一种简单的方法是获取绝对值并为每个元素添加一个负号,然后进行argsort。

l=np.array([1,-1,2])
print(np.argsort((-np.abs(x))))  #[2,1,0]

答案 9 :(得分:0)

一种优雅的方法如下-

ids = np.flip(np.argsort(avgDists))

这将为您提供按降序排列的元素的索引。 现在您可以使用常规切片...

top_n = ids[:n]