【问题标题】:How to get indices of a sorted array in Python如何在 Python 中获取已排序数组的索引
【发布时间】:2011-09-19 08:16:18
【问题描述】:

我有一个数字列表:

myList = [1, 2, 3, 100, 5]

现在如果我对该列表进行排序以获得[1, 2, 3, 5, 100]。 我想要的是元素的索引 按排序顺序排列的原始列表,即[0, 1, 2, 4, 3] --- ala MATLAB 的 sort 函数同时返回 价值和指数。

【问题讨论】:

  • @unutbu 这不是骗子(IMO)。这个问题与使用 Numpy.argsort() 并不矛盾
  • @amit:你说的“不矛盾”是什么意思?
  • @unutbu Numpy.argsort() 是这个问题的一个很好的答案,它可能是对链接的另一个线程的欺骗(你也关闭了,我认为你不应该有)但不是你提到的那个,因为 Numpy.argsort() 是这两个的好答案,但不是你提到的那个。
  • 不幸的是,这个问题在选择示例时存在严重缺陷,因为当输入只是无序的转置时,两种不同的阅读方式会给出相同的答案。

标签: python indexing sorted


【解决方案1】:
s = [2, 3, 1, 4, 5]
print([sorted(s, reverse=False).index(val) for val in s]) 

它甚至适用于具有重复元素的列表。

【讨论】:

    【解决方案2】:

    我用perfplot(我的一个项目)对这些进行了快速的性能检查,发现除了推荐其他任何东西都很难

    np.argsort(x)
    

    (注意对数刻度):


    重现情节的代码:

    import perfplot
    import numpy as np
    
    
    def sorted_enumerate(seq):
        return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]
    
    
    def sorted_enumerate_key(seq):
        return [x for x, y in sorted(enumerate(seq), key=lambda x: x[1])]
    
    
    def sorted_range(seq):
        return sorted(range(len(seq)), key=seq.__getitem__)
    
    
    b = perfplot.bench(
        setup=np.random.rand,
        kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, np.argsort],
        n_range=[2 ** k for k in range(15)],
        xlabel="len(x)",
    )
    b.save("out.png")
    

    【讨论】:

    • 很高兴看到最短的纯 python 解决方案是 PEP 所期望的最快的!
    【解决方案3】:

    首先将您的列表转换为:

    myList = [1, 2, 3, 100, 5]
    

    为列表项添加索引

    myList = [[0, 1], [1, 2], [2, 3], [3, 100], [4, 5]]
    

    下一个:

    sorted(myList, key=lambda k:k[1])
    

    结果:

    [[0, 1], [1, 2], [2, 3], [4, 5], [3, 100]]
    

    【讨论】:

      【解决方案4】:

      为此目的使用 Numpy 包的最简单方法

      import numpy
      s = numpy.array([2, 3, 1, 4, 5])
      sort_index = numpy.argsort(s)
      print(sort_index)
      

      但是如果你想要你的代码应该使用 baisc python 代码:

      s = [2, 3, 1, 4, 5]
      li=[]
        
      for i in range(len(s)):
            li.append([s[i],i])
      li.sort()
      sort_index = []
        
      for x in li:
            sort_index.append(x[1])
        
      print(sort_index)
      

      【讨论】:

        【解决方案5】:

        代码:

        s = [2, 3, 1, 4, 5]
        li = []
        
        for i in range(len(s)):
            li.append([s[i], i])
        li.sort()
        sort_index = []
        
        for x in li:
            sort_index.append(x[1])
        
        print(sort_index)
        

        试试这个,它对我有用,干杯!

        【讨论】:

          【解决方案6】:

          基本上你需要做一个argsort,你需要什么实现取决于你是想使用外部库(例如NumPy)还是你想保持纯Python而不依赖。

          你需要问自己的问题是:你想要的

          • 对数组/列表进行排序的索引
          • 元素在排序数组/列表中的索引

          不幸的是,问题中的示例并未明确说明所需的内容,因为两者都会给出相同的结果:

          >>> arr = np.array([1, 2, 3, 100, 5])
          
          >>> np.argsort(np.argsort(arr))
          array([0, 1, 2, 4, 3], dtype=int64)
          
          >>> np.argsort(arr)
          array([0, 1, 2, 4, 3], dtype=int64)
          

          选择argsort 实现

          如果您可以使用 NumPy,您可以简单地使用函数 numpy.argsort 或方法 numpy.ndarray.argsort

          其他一些答案中已经提到了没有 NumPy 的实现,所以我将根据the benchmark answer here 回顾一下最快的解决方案

          def argsort(l):
              return sorted(range(len(l)), key=l.__getitem__)
          

          获取对数组/列表进行排序的索引

          要获得对数组/列表进行排序的索引,您只需在数组或列表上调用argsort。我在这里使用 NumPy 版本,但 Python 实现应该给出相同的结果

          >>> arr = np.array([3, 1, 2, 4])
          >>> np.argsort(arr)
          array([1, 2, 0, 3], dtype=int64)
          

          结果包含获取排序数组所需的索引。

          由于排序后的数组将是[1, 2, 3, 4],因此 argsorted 数组包含原始中这些元素的索引。

          • 最小值是1,它位于原始索引1,因此结果的第一个元素是1
          • 2 在原始索引中位于索引2,因此结果的第二个元素是2
          • 3 在原始索引中位于索引0,因此结果的第三个元素是0
          • 最大值4,它在原始索引中的索引3,所以结果的最后一个元素是3

          获取元素在排序数组/列表中的索引

          在这种情况下,您需要申请argsort 两次

          >>> arr = np.array([3, 1, 2, 4])
          >>> np.argsort(np.argsort(arr))
          array([2, 0, 1, 3], dtype=int64)
          

          在这种情况下:

          • 原始的第一个元素是3,这是第三大值,因此它在排序后的数组/列表中具有索引2,因此第一个元素是2
          • 原始的第二个元素是1,这是最小值,因此它在排序后的数组/列表中有索引0,所以第二个元素是0
          • 原始的第三个元素是2,这是第二小的值,因此它在排序后的数组/列表中有索引1,所以第三个元素是1
          • 原始的第四个元素是4,这是最大值,所以它在排序的数组/列表中会有索引3,所以最后一个元素是3

          【讨论】:

            【解决方案7】:

            我们将创建另一个从 0 到 n-1 的索引数组 然后将其压缩到原数组中,然后根据原值排序

            ar = [1,2,3,4,5]
            new_ar = list(zip(ar,[i for i in range(len(ar))]))
            new_ar.sort()
            

            `

            【讨论】:

              【解决方案8】:

              其他答案是错误的。

              运行argsort 一次不是解决方案。 例如以下代码:

              import numpy as np
              x = [3,1,2]
              np.argsort(x)
              

              产生array([1, 2, 0], dtype=int64),这不是我们想要的。

              答案应该是运行argsort两次:

              import numpy as np
              x = [3,1,2]
              np.argsort(np.argsort(x))
              

              按预期提供array([2, 0, 1], dtype=int64)

              【讨论】:

              • 您的声明使x[2] (3) 成为最小元素,x[1] (1) 成为最大元素(因为对整数进行排序,从最小值到最大值)。此外,在 OP 示例中,单个 np.argsort([1, 2, 3, 100, 5]) 产生 array([0, 1, 2, 4, 3]),这似乎是 OP 想要的索引。
              • @0 0 你的例子是一个特定的例子。如果我们运行arr = [1,2,3,100, 5, 9] res = np.argsort(arr) print(res),那么我们会得到[0 1 2 4 5 3],这是错误的。
              • 我不清楚出了什么问题:arr[res] 产生 array([ 1, 2, 3, 5, 9, 100]),这似乎很好,因为结果数组是(递增)顺序的。
              • @0 0 for arr=[1,2,3,100, 5, 9],我希望输出为inds=[0,1,2,5,3,4],因为这是您对元素排序的顺序(越来越多) - 1 在 0 的位置,第 2 名,....,第 3 名 5 名,第 4 名 9 名。为了获得该输出 (inds),我需要运行两次 argsort,就像我提到的那样。
              • 所以这些索引是数组元素的一种排名(第 0 位、第 1 位等)。鉴于 OP 提到了 MATLAB's sort,我认为 OP 想要其他功能,就像通常使用 np.argsort 一样(可以使用 arr[np.argsort[arr]] 来获取排序数组,如上一个 MATLAB 示例)。您的答案适用于 this case / question
              【解决方案9】:
              myList = [1, 2, 3, 100, 5]    
              sorted(range(len(myList)),key=myList.__getitem__)
              
              [0, 1, 2, 4, 3]
              
              【解决方案10】:

              将 numpy 导入为 np

              FOR 索引

              S=[11,2,44,55,66,0,10,3,33]
              
              r=np.argsort(S)
              
              [output]=array([5, 1, 7, 6, 0, 8, 2, 3, 4])
              

              argsort 按排序顺序返回 S 的索引

              为了价值

              np.sort(S)
              
              [output]=array([ 0,  2,  3, 10, 11, 33, 44, 55, 66])
              

              【讨论】:

                【解决方案11】:

                如果你不想使用 numpy,

                sorted(range(len(seq)), key=seq.__getitem__)
                

                最快,如 here 所示。

                【讨论】:

                  【解决方案12】:

                  如果您使用的是 numpy,则可以使用 argsort() 函数:

                  >>> import numpy
                  >>> numpy.argsort(myList)
                  array([0, 1, 2, 4, 3])
                  

                  http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html

                  这将返回对数组或列表进行排序的参数。

                  【讨论】:

                  【解决方案13】:

                  enumerateitemgetter 更新答案:

                  sorted(enumerate(a), key=lambda x: x[1])
                  # [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]
                  

                  将列表压缩在一起:元组中的第一个元素是索引,第二个是值(然后使用元组的第二个值x[1]对其进行排序,x 是元组)

                  或者使用来自operatormodule`的itemgetter

                  from operator import itemgetter
                  sorted(enumerate(a), key=itemgetter(1))
                  

                  【讨论】:

                  • 在这种情况下,枚举似乎比 zip 更合适
                  【解决方案14】:

                  enumerate 的答案很好,但我个人不喜欢用于按值排序的 lambda。以下只是反转索引和值,并对其进行排序。所以它会首先按值排序,然后按索引。

                  sorted((e,i) for i,e in enumerate(myList))
                  

                  【讨论】:

                    【解决方案15】:

                    类似下一个:

                    >>> myList = [1, 2, 3, 100, 5]
                    >>> [i[0] for i in sorted(enumerate(myList), key=lambda x:x[1])]
                    [0, 1, 2, 4, 3]
                    

                    enumerate(myList) 给你一个包含 (index, value) 元组的列表:

                    [(0, 1), (1, 2), (2, 3), (3, 100), (4, 5)]
                    

                    通过将列表传递给 sorted 并指定一个函数来提取排序键(每个元组的第二个元素;这就是 lambda 的用途。最后,每个 的原始索引对列表进行排序sorted 元素是使用[i[0] for i in ...] 列表解析提取的。

                    【讨论】:

                    • 你可以使用itemgetter(1)代替lambda函数
                    • @gnibbler 指的是operator 模块中的itemgetter 函数,仅供参考。所以请from operator import itemgetter 使用它。
                    • 您可以使用zip获取排序列表和索引:sorted_items, sorted_inds = zip(*sorted([(i,e) for i,e in enumerate(my_list)], key=itemgetter(1)))
                    • @RomanBodnarchuk 这不起作用,x = [3,1,2]; numpy.argsort(x) 产生 [1,2,0]。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-01-07
                    • 2013-07-24
                    • 2011-06-19
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多