python - Python 中长列表的高效过滤、映射和归约操作

标签 python numpy filter list-comprehension generator

有一个包含 1000 万个数字的列表 (price_list),价格范围为 (0-100)。我想因此执行以下操作:

  1. 使用此条件过滤列表 (list_item < 30)
  2. 将每个 list_item 与固定数字相乘(映射)
  3. 计算所有元素的总和(归约)

这里是示例代码:

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/

相关文章:

python - 如何通知 PyCharm 自定义模块的位置?

python - 为什么我不应该使用异步(事件)IO

python - 运行 scipy.test ('full' 需要多长时间)?

r - 使用首先处理的年份创建新变量

ios - 在 Xcode 中使用带有 NSMutableArray 的过滤器函数

python - 三次Hermite样条插值python

python - 让 pylint 在 pylons/SA 模型中查找继承方法时遇到问题

python - Numpy 沿轴应用并获取行索引

google-sheets - 计算Google表格中每第n行单元格中出现的次数

asp.net-mvc - 如何解决 MVC 过滤器属性中的依赖注入(inject)