【问题标题】:Optimizing/improving speed of simple bit of Python code优化/提高简单 Python 代码的速度
【发布时间】:2020-07-21 09:49:27
【问题描述】:

我有一个客户列表,我希望返回一个排序过的客户列表 超过原始列表中的 5% 的时间。以下工作,但我需要优化它。不幸的是,我无法发现如何(大幅)提高时间效率。有什么建议吗?

def mostActive(customers):
    unique_customers = set(customers)
    count = len(customers)
    result = []
    for customer in unique_customers:
        if customers.count(customer) / count >= .05:
            result.append(customer)
    return sorted(result)

【问题讨论】:

  • 尝试列表理解。它会让你的代码更简单:)

标签: python performance optimization time


【解决方案1】:

在谈论性能时,测试是关键。这是其他答案中提供的一些代码的运行时间(在我的机器上,ofc),原始代码和基于 numpy 的答案(所有代码都在相同的数据上运行):

import numpy as np
from collections import Counter
import time

random_data = np.random.randint(0, 100, [100, 100000])

#### Original code
def mostActive(customers):
    unique_customers = set(customers)
    count = len(customers)
    result = []
    for customer in unique_customers:
        if customers.tolist().count(customer) / count >= .05: # had to add .tolist() to make it compatible with the data
            result.append(customer)
    return sorted(result)

start = time.time()
for i in range(100):
  _ = mostActive(random_data[i])
end = time.time()
print(f'Avg time: {(end-start)*10} ms') # would be /100*1000 -> simplified to *10
# Avg time: 1394.4847583770752 ms

#### Sorted + Counter

def mostActive(customers):
    return sorted(customer
                  for customer, count in Counter(customers).items()
                  if count / len(customers) >= .05)

start = time.time()
for i in range(100):
  _ = mostActive(random_data[i])
end = time.time()
print(f'Avg time: {(end-start)*10} ms')
# Avg time: 16.061179637908936 ms

#### Numpy

start = time.time()
for i in range(100):
  unique_elements, counts = np.unique(random_data[i], return_counts=True)
  active = sorted(unique_elements[counts > 0.05*len(random_data[i])])
end = time.time()
print(f'Avg time: {(end-start)*10} ms')
# Avg time: 3.5660386085510254 ms

不出所料,仅 numpy 的解决方案是 ligtning-fast(感谢底层的高性能 C 实现)

【讨论】:

    【解决方案2】:

    这是一个可能的解决方案:

    from collections import Counter
    
    def mostActive(customers):
        return sorted(customer
                      for customer, count in Counter(customers).items()
                      if count / len(customers) >= .05)
    

    使用collections.Counter 计算列表中每个元素的出现次数可显着提高性能。事实上,你只计算一次,在线性时间内。所以这里的复杂度是 O(n) + O(nlog(n)) (排序结果现在是瓶颈)。

    【讨论】:

      【解决方案3】:

      试试这个:

      list(set([name for name in customers if customers.count(name)/len(customers)>=0.05]))
      

      【讨论】:

      • 这并没有提高性能,因为您仍然每次都在计数。复杂度至少是二次方的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 2020-08-16
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      相关资源
      最近更新 更多