NumPy argsort - 它是在做什么?

165

为什么numpy会给出这个结果:

x = numpy.array([1.48,1.41,0.0,0.1])
print x.argsort()

>[2 3 1 0]

我本期望它做到这一点:

[3 2 0 1]

显然,我对函数的理解不够。


9
你为什么认为[3 2 0 1]是正确答案? - zwol
12
我刚才对输出的理解是相反的。也就是说,如果你取x的第一个元素,它应该在排序后的数组中的第三个位置,以此类推。 - user1276273
39
你的思维方式完全合理,我也有同样的问题。 - adrienlucca.net
7
[3 2 0 1] - 这是对值进行排名,你没有得到实际的索引。 - Lahiru Karunaratne
2
只需记住,输出指示原始数组中的位置,而您则认为它在排序后的数组中。这意味着output [0]是原始输入数组中最小元素所在的索引,而output [-1]是最大元素所在的索引。 - lincr
你试图对它进行排名而不是排序。 - ABCD
10个回答

172

根据文档

返回对数组进行排序后的索引。

  • 20.0 的索引。
  • 30.1 的索引。
  • 11.41 的索引。
  • 01.48 的索引。

20
a = x.argsort(), print x[a], we will get array([ 0. , 0.1 , 1.41, 1.48]) - Belter

51

[2, 3, 1, 0] 表示最小元素的索引为2,其次是索引3、1和0。

许多方法可以得到您要查找的结果:

import numpy as np
import scipy.stats as stats

def using_indexed_assignment(x):
    "https://dev59.com/WsKVzogBFxS5KdRj5vjM#5284703 (Sven Marnach)"
    result = np.empty(len(x), dtype=int)
    temp = x.argsort()
    result[temp] = np.arange(len(x))
    return result

def using_rankdata(x):
    return stats.rankdata(x)-1

def using_argsort_twice(x):
    "https://dev59.com/WsKVzogBFxS5KdRj5vjM#6266510 (k.rooijers)"
    return np.argsort(np.argsort(x))

def using_digitize(x):
    unique_vals, index = np.unique(x, return_inverse=True)
    return np.digitize(x, bins=unique_vals) - 1

例如,
In [72]: x = np.array([1.48,1.41,0.0,0.1])

In [73]: using_indexed_assignment(x)
Out[73]: array([3, 2, 0, 1])

这将检查它们是否都产生相同的结果:

x = np.random.random(10**5)
expected = using_indexed_assignment(x)
for func in (using_argsort_twice, using_digitize, using_rankdata):
    assert np.allclose(expected, func(x))

这些IPython %timeit 基准测试表明,对于大型数组,using_indexed_assignment 是最快的。
In [50]: x = np.random.random(10**5)
In [66]: %timeit using_indexed_assignment(x)
100 loops, best of 3: 9.32 ms per loop

In [70]: %timeit using_rankdata(x)
100 loops, best of 3: 10.6 ms per loop

In [56]: %timeit using_argsort_twice(x)
100 loops, best of 3: 16.2 ms per loop

In [59]: %timeit using_digitize(x)
10 loops, best of 3: 27 ms per loop

对于小数组,using_argsort_twice 可能更快:

In [78]: x = np.random.random(10**2)

In [81]: %timeit using_argsort_twice(x)
100000 loops, best of 3: 3.45 µs per loop

In [79]: %timeit using_indexed_assignment(x)
100000 loops, best of 3: 4.78 µs per loop

In [80]: %timeit using_rankdata(x)
100000 loops, best of 3: 19 µs per loop

In [82]: %timeit using_digitize(x)
10000 loops, best of 3: 26.2 µs per loop

注意,stats.rankdata 可以更好地控制如何处理相等值的元素。

2
你能否解释一下为什么两次使用argsort()可以得到排名? - Phani
2
@Phani:argsort 返回已排序数组的索引。已排序索引的索引是排名。这就是第二次调用 argsort 返回的内容。 - unutbu
3
第一个argsort返回一个排列(如果应用于数据将对其进行排序)。当argsort应用于该排列(或任何排列)时,它会返回反转的排列(如果这两个排列以任何顺序相互应用,则结果是Identity)。第二个排列如果应用于已经排序的数据数组,则会产生未排序的数据数组,即排名。 - Alex C
2
惊呆了!我终于明白了!它返回一个数组,其内容是原始数组索引的排序顺序。 - Jose A

4
正如文档所述,argsort:返回数组排序后的索引。这意味着argsort的第一个元素是应该被排序的第一个元素的索引,第二个元素是应该排在第二位的元素的索引,以此类推。您似乎想要的是值的等级顺序,这正是scipy.stats.rankdata提供的。请注意,如果排名相同,您需要考虑应该发生什么情况。

3

numpy.argsort(a, axis=-1, kind='quicksort', order=None)

返回一个数组排序后的下标。

在给定轴上使用kind关键字指定的算法执行间接排序。它返回一个与该索引数据形状相同的数组,按排序顺序沿着给定轴的索引。

例如,在Python中有一个值列表

listExample  = [0 , 2, 2456,  2000, 5000, 0, 1]

现在我们使用argsort函数:
import numpy as np
list(np.argsort(listExample))

输出将会是:
[0, 5, 6, 1, 3, 2, 4]

这是listExample中值的索引列表。如果将这些索引映射到相应的值,则会得到以下结果:
[0, 0, 1, 2, 2000, 2456, 5000]

我发现这个函数在很多地方都非常有用,例如,如果你想对列表/数组进行排序但不想使用list.sort()函数(即不改变列表中实际值的顺序),你可以使用这个函数。
更多详情请参阅此链接:https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html

1

如果有人想知道“为什么要argsort”,我的答案是“使用一个数组来对另一个数组进行排序”:

In [49]: a = np.array(list('asdf'))

In [50]: b = [3,2,0,1]

In [51]: np.argsort(b)
Out[51]: array([2, 3, 1, 0])

In [52]: a[np.argsort(b)]
Out[52]: array(['d', 'f', 's', 'a'], dtype='<U1')

这对于列数据非常有用,例如一个名字列和一个薪水列,你想看到N个最高薪水的人的名字。


1

输入:
import numpy as np
x = np.array([1.48,1.41,0.0,0.1])
x.argsort().argsort()

输出:
array([3, 2, 0, 1])


2
虽然这段代码片段可能是解决方案,但包括解释真的有助于提高您的帖子质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您的代码建议原因。 - peacetype

0

只是想通过代码直接对比原帖作者的理解与实际实现。

numpy.argsort 的定义是针对一维数组的:

x[x.argsort()] == numpy.sort(x) # this will be an array of True's

原帖作者最初认为它的定义是针对一维数组的:

x == numpy.sort(x)[x.argsort()] # this will not be True

注意:此代码不适用于一般情况(只适用于1D),此答案仅供说明目的。


x[x.argsort()] 不一定等同于 np.sort(x)。实际上,它们的形状甚至不一定相同。使用 2D 数组尝试一下就知道了。这只适用于 1D 数组。 - Nathan
1
我觉得那有点过于追求细节了。这个问题是关于一维数组的。这只是一种理解差异的方式,而不是要使用的字面代码。此外,当你有一个二维数组时,甚至不清楚你想要什么样的排序。你想要全局排序吗?如果不是,应该按哪个轴排序?无论如何,我已经添加了免责声明。 - Multihunter

0

np.argsort返回由“kind”(指定排序算法类型)给出的排序数组的索引。然而,当使用np.argmax时,如果使用列表,则返回列表中最大元素的索引。而np.sort则对给定的数组或列表进行排序。


0

首先,对数组进行排序。然后生成一个以数组初始索引为基础的新数组。


0

根据给定的数组索引[1.48,1.41,0.0,0.1],它返回相应的索引,即: 0.0是第一个元素,在索引[2]处。 0.1是第二个元素,在索引[3]处。 1.41是第三个元素,在索引[1]处。 1.48是第四个元素,在索引[0]处。 输出:

[2,3,1,0]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接