排序数组并返回已排序数组的原始索引

时间:2018-06-14 03:45:12

标签: python sorting permutation

给定一个numpy数组,如何在其中找到索引序列,以便对结果进行排序?

例如,给定x=[4,2,6],结果为[1,0,2],因为[x[1],x[0],x[2]]已排序。

我知道有许多像argsort()这样的Python函数可以完成这项工作,但我需要自己实现这个排序功能。有什么建议吗?

3 个答案:

答案 0 :(得分:5)

首先,您可以使用enumerate将任何可迭代的值转换为可转换的(索引,值)对。

但是如果你只是对它们进行排序,它会按索引排序,这并不是非常有用。您希望按每个(索引,值)对中的值进行排序。通常,在Python中,您可以通过将key function传递给sorted来实现。如该文档中的示例所示,itemgetter在此处提供了完美的关键功能。您可以轻松地修改自定义排序功能,以使用与sorted相同的方式使用键功能,但如果没有看到自定义排序功能,很难向您展示如何执行此操作。 1功能

但在这种情况下,您可以使用Decorate-Sort-Undecorate成语。你只想按每个(索引,值)对中的值排序,所以你要做的就是去装饰"反转对。而且,如果您只想要索引而不是值,那么只需删除值即可。

所以:

indexed = enumerate(arr)
decorated = ((value, index) for index, value in indexed)
sortedpairs = my_sort_function(decorated)
indices = np.fromiter(index for (value, index) in sortedpairs)

...或者,把它们放在一起:

sortedpairs = my_sort_function((value, index) for index, value in enumerate(arr))
indices = np.fromiter(index for (value, index) in sortedpairs)

(当然你可以把它作为一个单行,但我认为这两行是最好的可读性平衡。)

如果您不允许使用enumerate,则这是用您自己的功能替换的最简单的内置函数之一。事实上,文档甚至会告诉你如何做到这一点:

def my_enumerate(sequence, start=0):
    n = start
    for elem in sequence:
        yield n, elem
        n += 1

或者,因为您不需要自定义起始值:

def my_enumerate(sequence):
    n = 0
    for elem in sequence:
        yield n, elem
        n += 1

但是现在,你是否可以做同样的事情,同时仍然采取(至少一些)numpy的优势,将所有内容保持为数组而不是使用iterables?

不确定。我们可以做同样的事情enumerate,甚至将值放在底部,这样我们就不需要整个翻转步骤了:

decorated = np.stack((arr, np.arange(len(arr))))

...然后排序。我假设你的自定义排序功能对列进行排序。也许你需要传递一个axis参数,或者排序decorated.T,或者其他什么;你应该知道你自己的函数的API。

sorted_pairs = my_sorted_array_function(decorated)

现在,我们只需要索引行:

indices = sorted_pairs[1]

<子> 1。对于初始实施,只需将每x < y更改为key(x) < key(y),然后使其正常运行。然后,您可以通过缓存关键值来弄清楚如何优化它,这样您每个元素只能调用key一次,而不是每个元素调用log(N)次。

答案 1 :(得分:3)

举个例子,让我们进行冒泡排序(来自here)并添加索引跟踪:

def bubblesort(lst):
    "Sorts lst in place and returns it."
    args = list(range(len(lst))) # <- initial order of indices
    for passesLeft in range(len(lst)-1, 0, -1):
        for index in range(passesLeft):
            if lst[index] > lst[index + 1]:
                lst[index], lst[index + 1] = lst[index + 1], lst[index]
                args[index], args[index + 1] = args[index + 1], args[index] # swap indices too
    return lst, args

答案 2 :(得分:2)

如果我理解您的问题,您可以使用list-comprehension功能sorted

>>> import numpy as np
>>> np_array = np.array([4, 2, 6])
>>> sorted_index_pos = [index for index, num in sorted(enumerate(np_array), key=lambda x: x[-1])]
[1, 0, 2]