[英]Fast checking if a string can be converted to float or int in python
我需要将大数组中的所有字符串都转换为int或float类型,如果它们可以转换的话。 通常,人们建议使用try-except或regex方法(例如在检查字符串是否可以在Python中转换为float的方法 ),但是事实证明它非常慢。
问题是:如何以最快的方式编写该代码?
我发现有一个字符串的.isdigit()方法。 花车有类似的东西吗?
这是当前(慢速)代码。
result = []
for line in lines:
resline = []
for item in line:
try:
resline.append(int(item))
except:
try:
resline.append(float(item))
except:
resline.append(item)
result.append(resline)
return np.array(result)
还有一些证据( https://stackoverflow.com/a/2356970/3642151 )表明正则表达式的方法甚至更慢。
您的返回值表明您正在使用NumPy。 因此,您应该使用np.loadtxt或np.genfromtxt (带有dtype dtype=None
参数)将行加载到NumPy数组中。 dtype=None
参数将自动检测字符串是否可以转换为float
或int
。
np.loadtxt
是速度更快,需要内存少np.genfromtxt
,但需要你指定的dtype
-有没有dtype=None
自动D型检测选项。 请参阅Joe Kington的帖子进行比较 。
如果您发现使用np.loadtxt
或np.genfromtxt
加载CSV仍然太慢,则使用Panda的read_csv
函数要快得多 ,但是(当然)需要先安装Pandas ,结果是Pandas DataFrame ,而不是NumPy数组。 DataFrame具有许多不错的功能(并且可以转换为NumPy数组),因此您可能会发现这不仅在加载速度方面而且在数据处理方面都是一个优势。
顺便说一句,如果您未在通话中指定dtype
np.array(data)
然后np.array
对所有数据使用单个np.array
。 如果您的数据同时包含int和float,则np.array
将返回一个带有float np.array
的数组:
In [91]: np.array([[1, 2.0]]).dtype
Out[91]: dtype('float64')
更糟糕的是,如果您的数据包含数字和字符串,则np.array(data)
将返回字符串np.array(data)
的数组:
In [92]: np.array([[1, 2.0, 'Hi']]).dtype
Out[92]: dtype('S32')
因此,您检查所有字符串为ints
或floats
所有艰苦工作都会在最后一行被销毁。 np.genfromtxt(..., dtype=None)
通过返回结构化数组(具有异类dtype的数组np.genfromtxt(..., dtype=None)
来解决此问题。
尝试对您的Python脚本进行性能分析,您会发现try... except
, float
或int
并不是脚本中最耗时的调用。
import random
import string
import cProfile
def profile_str2float(calls):
for x in xrange(calls):
str2float(random_str(100))
def str2float(string):
try:
return float(string)
except ValueError:
return None
def random_str(length):
return ''.join(random.choice(string.lowercase) for x in xrange(length))
cProfile.run('profile_str2float(10**5)', sort='cumtime')
运行此脚本,我得到以下结果:
40400003 function calls in 14.721 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 14.721 14.721 <string>:1(<module>)
1 0.126 0.126 14.721 14.721 str2float.py:5(profile_str2float)
100000 0.111 0.000 14.352 0.000 str2float.py:15(random_str)
100000 1.413 0.000 14.241 0.000 {method 'join' of 'str' objects}
10100000 4.393 0.000 12.829 0.000 str2float.py:16(<genexpr>)
10000000 7.115 0.000 8.435 0.000 random.py:271(choice)
10000000 0.760 0.000 0.760 0.000 {method 'random' of '_random.Random' objects}
10000000 0.559 0.000 0.559 0.000 {len}
100000 0.242 0.000 0.242 0.000 str2float.py:9(str2float)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
从“累积时间”统计信息中可以看到, str2float
函数并没有消耗太多的CPU时间,在100.000次调用中,它几乎不使用250ms。
所有归纳都是错误的(具有讽刺意味的是)。 不能说try: except:
总是比正则表达式快,反之亦然。 在您的情况下,正则表达式并不过分,比try: except:
方法要快得多。 但是,根据您对问题的评论部分中的讨论,我继续并实现了一个C库,该库有效地执行了此转换(因为我在SO上经常看到此问题); 该库称为fastnumbers 。 以下是使用try: except:
方法,正则表达式和fastnumbers
进行的时序测试。
from __future__ import print_function
import timeit
prep_code = '''\
import random
import string
x = [''.join(random.sample(string.ascii_letters, 7)) for _ in range(10)]
y = [str(random.randint(0, 1000)) for _ in range(10)]
z = [str(random.random()) for _ in range(10)]
'''
try_method = '''\
def converter_try(vals):
resline = []
for item in vals:
try:
resline.append(int(item))
except ValueError:
try:
resline.append(float(item))
except ValueError:
resline.append(item)
'''
re_method = '''\
import re
int_match = re.compile(r'[+-]?\d+$').match
float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match
def converter_re(vals):
resline = []
for item in vals:
if int_match(item):
resline.append(int(item))
elif float_match(item):
resline.append(float(item))
else:
resline.append(item)
'''
fn_method = '''\
from fastnumbers import fast_real
def converter_fn(vals):
resline = []
for item in vals:
resline.append(fast_real(item))
'''
print('Try with non-number strings', timeit.timeit('converter_try(x)', prep_code+try_method), 'seconds')
print('Try with integer strings', timeit.timeit('converter_try(y)', prep_code+try_method), 'seconds')
print('Try with float strings', timeit.timeit('converter_try(z)', prep_code+try_method), 'seconds')
print()
print('Regex with non-number strings', timeit.timeit('converter_re(x)', prep_code+re_method), 'seconds')
print('Regex with integer strings', timeit.timeit('converter_re(y)', prep_code+re_method), 'seconds')
print('Regex with float strings', timeit.timeit('converter_re(z)', prep_code+re_method), 'seconds')
print()
print('fastnumbers with non-number strings', timeit.timeit('converter_fn(x)', prep_code+fn_method), 'seconds')
print('fastnumbers with integer strings', timeit.timeit('converter_fn(y)', prep_code+fn_method), 'seconds')
print('fastnumbers with float strings', timeit.timeit('converter_fn(z)', prep_code+fn_method), 'seconds')
print()
输出在我的机器上如下所示:
Try with non-number strings 55.1374599934 seconds
Try with integer strings 11.8999788761 seconds
Try with float strings 41.8258318901 seconds
Regex with non-number strings 11.5976541042 seconds
Regex with integer strings 18.1302199364 seconds
Regex with float strings 19.1559209824 seconds
fastnumbers with non-number strings 4.02173805237 seconds
fastnumbers with integer strings 4.21903610229 seconds
fastnumbers with float strings 4.96900391579 seconds
一些事情很清楚
try: except:
非数字输入非常慢; 正则表达式可以轻松击败 try: except:
如果不需要引发异常,则效率更高 fastnumbers
因此,如果您不想使用fastnumbers
,则需要评估您是否更有可能遇到无效字符串或有效字符串,并以此为基础选择算法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.