将列表中的项目转换为整数并求和的最有效方法

4

我正在做类似这样的事情来总结一行中的多个元素:

for line in open(filename, 'r'):
   big_list = line.strip().split(delim)
   a = sum(int(float(item)) for item in big_list[start:end] if item)  
   # do some other stuff

这是一行行地处理一个大文件,其中可能会缺少某些项,即等于''。如果使用上述语句计算a,脚本的速度比不使用该语句要慢得多。有没有方法可以加快速度?


2
因为int('1.0')会引发异常。 - Bob
1
你正在求和哪种数据,是否存在像3.4这样的实数? - Padraic Cunningham
1
@jonrsharpe,那个更慢。 - Padraic Cunningham
1
一些快速的 timeit 测试表明,我可能给你错误的建议,跳过使用 [] - 把列表传递给 sum 稍微快一点。不过那里的收益可能会很小。 - jonrsharpe
1
有几个问题。我不确定numpy或pandas是否处理无法放入内存的非常大的文件。假设它们可以,我有几个相当复杂的条件来决定是否处理一行。因此,我认为我不能使用它们。 - Bob
显示剩余13条评论
2个回答

0

正如Padraic所评论的那样,使用filter来去除空字符串,然后删除“if item”:

>>> import timeit
>>> timeit.timeit("sum(int(float(item)) for item in ['','3.4','','','1.0'] if item)",number=10000)
0.04612559381553183
>>> timeit.timeit("sum(int(float(item)) for item in filter(None, ['','3.4','','','1.0']))",number=10000)
0.04827789913997549
>>> sum(int(float(item)) for item in filter(None, ['','3.4','','','1.0']))
4
>>> 

在这个例子中是适得其反的,但在你的情境下可能会有所减少。测量一下看看。

另请参阅此答案


0

这还没有经过测试,但直观上我会认为跳过中间的浮点数转换会有帮助。您想获取小数点左侧的整数,因此我建议尝试直接使用正则表达式进行操作:

import re

pattern = re.compile("\d+")

然后用正则表达式匹配替换浮点数解析:

sum(int(pattern.search(item).group(0)) for item in big_list[start:end] if item)

如果您不需要保留旧的十进制字符串,也可以在构建big_list时即时获取它们。例如,假设我们有以下行:"6.0,,1.2,3.0,"。我们可以像这样获取匹配项:
delim = ","
pattern = re.compile("(\d+)\.\d+|" + re.escape(delim) + re.escape(delim) + "|$")

这个模式在该行上的结果将是:['6', '', '1', '3', ''],然后可以像往常一样进行切片和过滤,而无需进行浮点解析。
for line in open(filename, 'r'):
    big_list = pattern.findall(line)
    a = sum(int(item) for item in big_list[start:end] if item)

实际上,我已经删除了强制转换为int的操作。我只是检查是否至少有一个非零元素。否则,我会丢弃该行。 - Bob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接