有一个包含 1000 万个数字的列表 (price_list),价格范围为 (0-100)。我想因此执行以下操作:
- 使用此条件过滤列表 (list_item < 30)
- 将每个 list_item 与固定数字相乘(映射)
- 计算所有元素的总和(归约)
这里是示例代码:
import time import numpy as np from functools import reduce with open('price_list.txt') as f: price_list = f.read().split('\n') price_list = np.array(price_list).astype(int) # convert string to int
我尝试了以下选项:
使用 NumPy 模块(0.1069948673248291 秒):
total = np.sum(price_list[price_list < 30] * 1.05)
使用暴力循环(9.485718965530396 秒)
使用过滤器、映射和归约函数(10.078220844268799 秒):
total = reduce(lambda x,y: x+y,map(lambda x: x * 1.05, filter(lambda x: x < 30, price_list)) )
使用列表理解(8.609008073806763 秒):
total= sum([x * 1.05 for x in price_list if x <30])
使用生成器(8.780538320541382 秒):
total= sum((x * 1.05 for x in price_list if x <30))
很明显,NumPy 模块在这些操作中速度非常快。是否有任何替代解决方案可以使用 Python 内置函数和功能更快地运行此代码?
最佳答案
使用三个新解决方案进行基准测试(从您从文件中获取的字符串列表开始):
4.1 s original_numpy
11.6 s original_listcomp
4.8 s better_listcomp
1.7 s even_better_listcomp
0.6 s counter
better_listcomp
与你的唯一区别是我添加了 .tolist()
,因此 price_list
实际上是一个列表,Python 得到使用 Python 整数而不是 NumPy 整数,这要快得多。 (将数组称为列表确实是错误的标签)。
even_better_listcomp
更进一步,甚至根本没有经过 NumPy。 (它与 1.05 相乘一次,相加之后。)
counter
更进一步,延迟从字符串到 int 的转换,直到对价格字符串进行计数之后。
代码(Try it online!):
def better_listcomp(price_list):
price_list = np.array(price_list).astype(int).tolist()
return sum([x * 1.05 for x in price_list if x < 30])
def even_better_listcomp(price_list):
prices = map(int, price_list)
return sum([x for x in prices if x < 30]) * 1.05
def counter(price_list):
return sum(int(k) * v for k, v in Counter(price_list).items() if int(k) < 30) * 1.05
def original_numpy(price_list):
price_list = np.array(price_list).astype(int)
return np.sum(price_list[price_list < 30] * 1.05)
def original_listcomp(price_list):
price_list = np.array(price_list).astype(int)
return sum([x * 1.05 for x in price_list if x < 30])
funcs = original_numpy, original_listcomp, better_listcomp, even_better_listcomp, counter
from time import time
import numpy as np
from collections import Counter
price_list = list(map(str, range(1, 100))) * 101010
for _ in range(2):
for f in funcs:
t = time()
f(price_list)
print(f'{time() - t :4.1f} s ', f.__name__)
print()
关于python - Python 中长列表的高效过滤、映射和归约操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73185139/