我在Python中有大约5000万个字符串列表,如下所示:
["1", "1.0", "", "foobar", "3.0", ...]
我需要将这些转换为浮动列表和Nones,如下所示:
[1.0, 1.0, None, None, 3.0, ...]
目前我使用的代码如下:
def to_float_or_None(x):
try:
return float(x)
except ValueError:
return None
result = []
for record in database:
result.append(map(to_float_or_None, record))
to_float_or_None函数总共花费大约750秒(根据cProfile)...有没有更快的方法来执行从字符串列表到浮点数/ Nones列表的转换?
更新
我已经将to_float_or_None
函数确定为主要瓶颈。我发现使用map
和使用列表推导之间的速度没有显着差异。
我应用了Paulo Scardine的提示来检查输入,它已经节省了1/4的时间。
def to_float_or_None(x):
if not(x and x[0] in "0123456789."):
return None
try:
return float(x)
except:
return None
发电机的使用对我来说是新的,所以感谢您提示Cpfohl和Lattyware!这确实加快了文件的读取速度,但我希望通过将字符串转换为浮点数/ Nones来节省一些内存。
答案 0 :(得分:2)
编辑:我刚刚意识到我误解了这个问题,我们正在讨论列表清单,而不仅仅是清单。更新以适应这种情况。
你可以在这里使用list comprehension来制作一些faster的东西,并且更好阅读:
def to_float_or_None(x):
try:
return float(x)
except ValueError:
return None
database = [["1", "1.0", "", "foobar", "3.0"], ["1", "1.0", "", "foobar", "3.0"]]
result = [[to_float_or_None(item) for item in record] for record in database]
给我们:
[[1.0, 1.0, None, None, 3.0], [1.0, 1.0, None, None, 3.0]]
编辑:正如评论中Paolo Moretti所述,如果您想要绝对最快的结果,那么使用map
may be faster,因为我们没有使用lambda函数:
def to_float_or_None(x):
try:
return float(x)
except ValueError:
return None
database = [["1", "1.0", "", "foobar", "3.0"], ["1", "1.0", "", "foobar", "3.0"]]
result = [list(map(to_float_or_None, record)) for record in database]
给我们相同的结果。但是,我要注意,过早优化是一件坏事。如果你已经将此确定为应用程序中的瓶颈,那么公平,但除此之外坚持使用更快的可读性。
我们仍然使用外部循环的列表推导,因为我们需要一个lambda函数再次使用map
,因为它依赖于record
:
result = map(lambda record: map(to_float_or_None, record), database)
当然,如果你想懒惰地评估这些,你可以使用生成器表达式:
((to_float_or_None(item) for item in record) for record in database)
或者:
(map(to_float_or_None, record) for record in database)
除非您一次需要整个列表,否则这将是首选方法。
答案 1 :(得分:2)
我不了解性能方面,但这应该适用于您的情况。
list_floats = [to_float_or_None(item) for item in original_list]
答案 2 :(得分:2)
或者,如果您在列表中确实拥有那么多数据,可以使用pandas系列和apply()
lambda函数进行转换:
import pandas,re
inlist = ["1", "1.0", "", "foobar", "3.0"] # or however long...
series = pandas.Series(inlist)
series.apply(lambda x: float(x) if re.match("^\d+?(\.\d+?)*$",x) else None)
Out[41]:
0 1
1 1
2 NaN
3 NaN
4 3
许多其他优点 - 尤其是之后指定您希望如何处理missing values ...
答案 3 :(得分:2)
到目前为止给出的答案并没有完全回答这个问题。 try...catch
与验证if then
相比可能会导致不同的效果(请参阅:https://stackoverflow.com/a/5591737/456188)。总结答案:取决于失败与成功的比率以及两种情况下失败和成功的 MEASURED 时间。基本上我们不能回答这个问题,但我们可以告诉你如何:
if/then
进行同等测试的try/catch
优化它,然后测量to_float_or_None
两个版本失败100次所需的时间,并测量两者的使用时间to_float_or_None
的版本要成功100次。关于列表理解问题的附注:
根据您是否希望能够对其结果进行索引,或者您是否只想迭代它,生成器表达式实际上甚至比列表理解更好(只需替换[
{ {1}} ]
(
个字符的字符。
基本上没有时间创建,并且to_float_or_None(这是一个昂贵的部分)的实际执行可以延迟到它需要的结果。
由于许多原因,这很有用,但如果您需要对其进行索引,则无法使用。它将但是,允许您使用生成器压缩原始集合,这样您仍然可以访问原始字符串及其float_or_none结果。