【问题标题】:Equivalent of Numpy.argsort() in basic python? [duplicate]相当于基本 python 中的 Numpy.argsort()? [复制]
【发布时间】:2011-03-23 21:06:43
【问题描述】:

是否有 Python 的内置函数在 python.array 上执行 argsort()numpy.array 上的作用?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    我对上面的建议进行了计时,这是我的结果。

    import timeit
    import random
    import numpy as np
    
    def f(seq):
        # http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3383106#3383106
        #non-lambda version by Tony Veijalainen
        return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]
    
    def g(seq):
        # http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3383106#3383106
        #lambda version by Tony Veijalainen
        return [x for x,y in sorted(enumerate(seq), key = lambda x: x[1])]
    
    
    def h(seq):
        #http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3382369#3382369
        #by unutbu
        return sorted(range(len(seq)), key=seq.__getitem__)
    
    
    seq = list(range(10000))
    random.shuffle(seq)
    
    n_trials = 100
    for cmd in [
            'f(seq)', 'g(seq)', 'h(seq)', 'np.argsort(seq)',
            'np.argsort(seq).tolist()'
            ]:
        t = timeit.Timer(cmd, globals={**globals(), **locals()})
        print('time for {:d}x {:}: {:.6f}'.format(n_trials, cmd, t.timeit(n_trials)))
    

    输出

    time for 100x f(seq): 0.323915
    time for 100x g(seq): 0.235183
    time for 100x h(seq): 0.132787
    time for 100x np.argsort(seq): 0.091086
    time for 100x np.argsort(seq).tolist(): 0.104226
    

    问题大小相关分析给出here

    【讨论】:

    • 有趣 - 可能平均值比 3 的“最佳”更重要(?)
    • 平均值受异常值影响。您不希望结果被其他正在运行的程序或硬件缓存未命中事件污染。
    • 对于未来的读者,%timeit 报告了 3 个平均 100 个循环中的最佳平均值。
    【解决方案2】:

    没有内置函数,但很容易从 Python 提供的极好的工具中组装一个:

    def argsort(seq):
        # http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python
        return sorted(range(len(seq)), key=seq.__getitem__)
    
    x = [5,2,1,10]
    
    print(argsort(x))
    # [2, 1, 0, 3]
    

    它同样适用于 Python array.arrays:

    import array
    x = array.array('d', [5, 2, 1, 10])
    print(argsort(x))
    # [2, 1, 0, 3]
    

    【讨论】:

    • 除了使用(理论上是私有的)getitem,还可以使用operator.itemgetter / operator.attrgetter docs.python.org/library/operator.html
    • 如果operator.itemgetter 可以用作__getitem__ 的替代品,我想我同意你的看法,但据我所知,operator.itemgetter 也需要将其包装在 lambda 表达式中。如果可以的话,我宁愿避免使用额外的lambda
    • @Ender: itemgetter 在这里没有用处:x.__getitem__(i) 返回x[i],而itemgetter(x)(i) 将返回i[x]
    【解决方案3】:

    找到了这个问题,但需要 argsort 来获取基于对象属性的对象列表。

    扩展 unutbu 的答案,这将是:

    sorted(range(len(seq)), key = lambda x: seq[x].sort_property)
    

    【讨论】:

      【解决方案4】:

      我的枚举替代方案:

      def argsort(seq):
          return [x for x,y in sorted(enumerate(seq), key = lambda x: x[1])]
      
      seq=[5,2,1,10]
      print(argsort(seq))
      # Output:
      # [2, 1, 0, 3]
      

      最好使用来自https://stackoverflow.com/users/9990/marcelo-cantos 的回答来回答线程python sort without lambda expressions

      [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]
      

      【讨论】:

        猜你喜欢
        • 2011-05-16
        • 2011-04-18
        • 2015-04-21
        • 2014-10-23
        • 2015-06-15
        • 1970-01-01
        • 2020-04-13
        • 1970-01-01
        • 2011-12-17
        相关资源
        最近更新 更多