粗糙的阿尔戈特-它在做什么?

为什么麻木给出这样的结果:

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


>[2 3 1 0]

当我期望它做到这一点:

[3201]

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

107335 次浏览

[2, 3, 1, 0]表示最小的元素位于索引2,第二个最小的元素位于索引3,然后是索引1,最后是索引0。

有很多种方法得到你想要的结果:

import numpy as np
import scipy.stats as stats


def using_indexed_assignment(x):
"https://stackoverflow.com/a/5284703/190597 (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://stackoverflow.com/a/6266510/190597 (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使您能够更好地控制如何处理等值的元素。

正如 文件所说,argsort:

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

这意味着 argsort 的第一个元素是应该首先排序的元素的索引,第二个元素是应该第二个元素的索引,等等。

您似乎想要的是值的排名顺序,这是由 scipy.stats.rankdata提供的。请注意,您需要考虑如果队伍中存在联系,应该发生什么情况。

根据 文件

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

  • 20.0的指数。
  • 30.1的指数。
  • 11.41的指数。
  • 01.48的指数。

首先,对数组进行排序,然后用数组的初始索引生成一个数组。

只是想用代码直接对比 OP 的原始理解和实际实现。

numpy.argsort的定义如下:

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

OP 最初认为它的定义是这样的,对于1D 数组:

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

注意: 这个代码在一般情况下不起作用(只适用于1D) ,这个答案纯粹是为了说明。

输入:
导入 numpy 作为 np
X = np.array ([1.48,1.41,0.0,0.1])
Argsort ()

产出:
Array ([3,2,0,1])

Argsort 返回“ kind”(指定排序算法的类型)给出的排序数组的索引。但是,当列表与 np.argmax 一起使用时,它返回列表中最大元素的索引。而 np.sort 则对给定的数组 list 进行排序。

Argsort (a,axis =-1,kind = ‘ Quick sort’,order = Nothing)

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

使用 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]

这是 listSample 中的值的索引列表如果你将这些索引映射到相应的值,那么我们将得到如下结果:

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

(我发现这个函数在许多地方非常有用,例如。如果您想对 list/array 进行排序,但不想使用 list.sort ()函数(即不改变列表中实际值的顺序) ,可以使用这个函数

有关详情,请参阅以下连结: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html

它根据给定的数组索引 [1.48,1.41,0.0,0.1]返回索引,这意味着: 0.0是索引[2]中的第一个元素。 0.1是索引[3]中的第二个元素。 1.41是索引[1]中的第三个元素。 1.48是索引[0]中的第四个元素。 产出:

[2,3,1,0]

对于那些想知道“为什么是 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 个薪水最高的人的名字。