【问题标题】:Quickly rank variables in python在python中快速排列变量
【发布时间】:2015-01-03 05:08:07
【问题描述】:

我想知道对变量进行排序的最快方法是什么?我有 4 个整数变量,我需要快速对它们进行排名。这个过程需要运行很多很多次,所以它需要很快。我尝试使用计数器和 counter().most_common() 函数,该函数运行良好,但比仅使用单个变量计数要慢。这是我正在运行的示例。

A = 15
B = 10
C = 5
D = 10

def get_highest(A,B,C,D):
    count = A
    label = 'A'
    if B >= count:
        count = B
        label = 'B'
    if C >= count:
        count = C
        label = 'C'
    if D >= count:
        count = D
        label = 'D'

    return count, label

highest, label = get_highest(A,B,C,D)
if label == 'A':
    A=0
if label == 'B':
    B=0
if label == 'C':
    C=0
if label == 'D':
    D=0
second_highest, label = get_highest(A,B,C,D)

我继续,直到我得到所有变量的排名。我想知道是否有更快的方法来做到这一点?我也想在 cython 中实现这一点,因此在 cython 中实现时可以加速的答案将不胜感激。

【问题讨论】:

  • 为什么不使用数组?
  • 你怎么知道什么更快?你是如何为你尝试过的不同事情计时的?

标签: python cython ranking


【解决方案1】:

这里有一个更快的替代函数:

import operator

def get_highest(A,B,C,D):
    return max(zip((A, B, C, D), 'ABCD'), key=operator.itemgetter(0))

但是,如果您的目标是使最大值变量归零,那么您最好让函数做更多的事情:

def max_becomes_zero(A, B, C, D):
    temp = [A, B, C, D]
    maxind, maxval = max(enumerate(temp), key=operator.itemgetter(1))
    maxname = 'ABCD'[maxind]
    temp[maxind] = 0
    return temp, maxval, maxname

如下调用:

(A, B, C, D), highest, label = max_becomes_zero(A, B, C, D)

补充:有些人可能想知道(并且确实在 cmets 中询问过)operator.itemgetter 与 lambda 的相对速度。答:不用怀疑,测量。这就是 Python 标准库中的 timeit 模块适用于...:

$ python -mtimeit -s'a="something"' 'max(enumerate(a), key=lambda x: x[1])'
1000000 loops, best of 3: 1.56 usec per loop
$ python -mtimeit -s'a="something"; import operator' 'max(enumerate(a), operator.itemgetter(1))'
1000000 loops, best of 3: 0.363 usec per loop

如您所见,在这种特殊情况下(在我的 Linux 工作站上,使用 Python 2.7.9),整个操作的加速令人印象深刻——快了 4 倍以上,每次重复节省了超过一微秒。

更一般地说,尽可能避免lambda会让你更快乐。

注意:对实际操作进行计时很重要——仅将aimport的初始化等初步操作放在启动中,即在-s标志中在python -mtimeit 形式的命令行中(推荐)使用timeit;我怀疑这个错误显然是阻止评论者复制这些结果的原因(只是猜测,因为所述评论者没有向我们展示了正在计时的确切代码,当然)。

【讨论】:

  • perator.itemgetter(1)(使用导入运算符)比lambda x : x[1] 快吗?
  • @Kasra,测量它——最好是python -mtimeit。我最好编辑答案以显示如何做到这一点......
  • 我这样做 lambda 更快,using operator : 0.0570709705353 using lambda : 0.00878500938416 for timeit(stmt=s1, number=100000 如果你知道原因亲爱的 alex,我将不胜感激!
  • @Kasra,您的数据无法解释(s1 是什么?近括号在哪里?-)。看看我的,现在在我的答案的结尾。
  • 您没有显示s1s2,所以很可能是您错误地重复 操作,例如`import
【解决方案2】:

以下在我的机器上花费不到 3µs 来完成整个排名:

In [43]: [name for (val, name) in sorted(zip((A, B, C, D), "ABCD"))][::-1]
Out[43]: ['A', 'D', 'B', 'C']

In [44]: %timeit [name for (val, name) in sorted(zip((A, B, C, D), "ABCD"))][::-1]
100000 loops, best of 3: 2.71 us per loop

或者这个怎​​么样(我希望我的比较是正确的:-)):

def rank1(A, B, C, D):
  lA, lB, lC, lD = "A", "B", "C", "D"
  if A < B:
    A, B, lA, lB = B, A, lB, lA
  if C < D:
    C, D, lC, lD = D, C, lD, lC
  if A < C:
    A, C, lA, lC = C, A, lC, lA
  if B < D:
    B, D, lB, lD = D, B, lD, lB
  if B < C:
    B, C, lB, lC = C, B, lC, lB
  return (A, B, C, D), (lA, lB, lC, lD)

整个排名770ns:

In [6]: %timeit rank1(A, B, C, D)
1000000 loops, best of 3: 765 ns per loop

【讨论】:

    【解决方案3】:

    可能值得尝试sort 变量:

    ordered = sorted(list(zip("ABCD", (A, B, C, D))), key=lambda x: x[1])
    
    >>> print(ordered)
    [('C', 5), ('B', 10), ('D', 10), ('A', 15)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      • 2021-07-21
      • 2018-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-20
      相关资源
      最近更新 更多