在Python中将值强制转换为各自数据类型的最快方法
我有一个值列表-所有字符串。我想将这些值转换为各自的数据类型。我将值映射到可用的类型信息 有三种不同的数据类型:int、str和datetime。 代码需要能够处理带有数据的错误情况 我正在做一些类似于:-在Python中将值强制转换为各自数据类型的最快方法,python,performance,casting,Python,Performance,Casting,我有一个值列表-所有字符串。我想将这些值转换为各自的数据类型。我将值映射到可用的类型信息 有三种不同的数据类型:int、str和datetime。 代码需要能够处理带有数据的错误情况 我正在做一些类似于:- tlist = [ 'some datetime value', '12', 'string', .... ] #convert it to: [ datetime object, 12, 'string', ....] error_data = ['', ' ', '?', ...]
tlist = [ 'some datetime value', '12', 'string', .... ]
#convert it to: [ datetime object, 12, 'string', ....]
error_data = ['', ' ', '?', ...]
d = { 0: lambda x: datetime.strptime(x,...) if x not in error_data else x,
1: lambda x: int(x) if x not in error_data else 0,
2: lambda x: x
...
}
result = [ d[i](j) for i, j in enumerate(tlist) ]
要转换的列表非常长,比如180个值,我需要对数千个这样的列表进行转换。上述代码的性能非常差。最快的方法是什么
谢谢因为您知道要转换到的类型,所以您可能无法从尝试优化转换中获得性能提升。性能不佳可能是由于反复迭代
错误\u数据
。如果可能,将您的错误\u数据
列表重建为集合
,以利用该类型的性质:
error_set = set((err, None) for err in error_data)
那就照你一直做的去做吧。进一步的改进需要对代码进行分析,以确定实际花费的时间。我不知道这是否会更快,但对我来说更清楚:
tlist = [ 'some datetime value', '12', 'string', .... ]
#convert it to: [ datetime object, 12, 'string', ....]
error_data = set(['', ' ', '?', ...])
def s(x):
return x
def d(x):
return datetime(x) if x not in error_data else x
def i(x):
return int(x) if x not in error_data else 0
types = [ d, i, s, s, s, i, i, d, i, ... ]
result = [ t(x) for t, x in zip(types, tlist) ]
正如其他人提到的,我正在使用一组错误值,这将比您的列表更快。类似于:
>>> values = ["12", "a", "bcd", "2.2"]
>>> types = [int, int, str, float]
>>> defaults = {int: 0, float: 0.0}
>>> res = []
>>> for v, f in itertools.izip(values, types): #Just use zip for Python 3+.
try:
res.append(f(v))
except ValueError:
res.append(defaults[f])
>>> print(res)
[12, 0, 'bcd', 2.2]
编辑:
这不处理日期时间值。我的解决方案是使用str
,并在循环后转换为datetime,如:
res[0] = datetime.strptime(res[0], "...")
获取和设置列表项都有O(1)复杂性,因此这应该不是问题。如果您的datetime值始终一致,为什么不让类型转换处理您试图在错误数据中管理的无效数据呢。这并不像某些解决方案那个么吸引人,但它使基于列表中数据的位置管理类型转换更易于维护和扩展
def convert(position, val):
if position == 0:
try:
return datetime.strptime(val, '%Y-%m-%d %H:%M:%S') # assuming date is in a constant format
except ValueError:
return val
elif position in (1, 15, 16): # assuming that you have other int values in other "columns"
try:
return int(val)
except ValueError:
return 0
else: # string type
return val
result = [convert(i,j) for i, j in enumerate(tlist)]
您的代码中存在不一致之处: 如果列表中的所有元素都是字符串,则不能在x为字符串的情况下编写
datetime(x)
编辑
它没有描绘任何东西,因为它是不协调的。代码中不存在的内容的复杂性并不能证明代码中存在的奇怪之处。我想,只要您不解释如何将字符串作为参数传递给函数datetime.datetime(),就没有人能够帮助您
编辑
我认为最好在读取文件时直接创建列表
我写了一个例子:
首先,我用以下代码创建了一个CSV文件:
import csv
from random import randint,choice
from time import gmtime
xx = ['Whose', 'all', 'birth', 'just', 'infant', 'William',
'dearest', 'rooms', 'find', 'Deserts', 'saucy', 'His',
'how', 'considerate', 'only', 'other', 'Houses', 'has',
'Fanny', 'them', 'his', 'very', 'dispense', 'early',
'words', 'not', 'thus', 'now', 'pettish', 'Worth']
def gen(n):
for i in xrange(n):
yield ['AAAA','%d/%02d/%02d %02d:%02d:%02d' % gmtime(randint(0,80000000))[0:6],'@@@']
yield ['BBBB',randint(100,999),'^^^^^^']
yield ['CCCC',choice(xx),'-----------------']
with open('zzz.txt','wb') as f:
writ = csv.writer(f, delimiter='#')
writ.writerows(x for x in gen(60))
CSV文件的结构如下所示:
AAAA#1972/02/11 08:53:53#@@@
BBBB#557#^^^^^^
CCCC#dearest#-----------------
AAAA#1971/10/15 06:55:20#@@@
BBBB#668#^^^^^^
CCCC#?#-----------------
AAAA#1972/07/13 11:10:05#@@@
BBBB#190#^^^^^^
CCCC#infant#-----------------
AAAA#1971/11/22 19:31:42#@@@
BBBB#202#^^^^^^
CCCC##-----------------
AAAA#1971/06/12 05:48:39#@@@
BBBB#81#^^^^^^
CCCC#find#-----------------
AAAA#1970/12/09 06:26:29#@@@
BBBB#72#^^^^^^
CCCC#find#-----------------
AAAA#1972/07/05 10:45:32#@@@
BBBB#270#^^^^^^
CCCC#rooms#-----------------
AAAA#1972/06/23 05:52:20#@@@
BBBB#202#^^^^^^
CCCC##-----------------
AAAA#1972/03/21 23:06:47#@@@
BBBB#883#^^^^^^
CCCC#William#-----------------
...... etc
下面的代码以与所需类似的方式提取数据
不需要字典,一个元组就足够了。根据创建的CSV文件的结构,我定义了funcs=60*(to_dt,int,lambda x:x)
,但您将使用字典值(排序)的连续函数
结果
1972-02-11 08:53:53 557 dearest
1971-10-15 06:55:20 668 ?
1972-07-13 11:10:05 190 infant
1971-11-22 19:31:42 202
1971-06-12 05:48:39 81 find
1970-12-09 06:26:29 72 find
1972-07-05 10:45:32 270 rooms
1972-06-23 05:52:20 202
1972-03-21 23:06:47 883 William
1970-02-08 23:47:26 617
1970-10-08 09:09:33 387 William
1971-04-30 11:05:07 721 ?
1970-02-12 11:57:48 827 Deserts
1972-03-27 21:30:39 363 just
1971-06-02 00:23:52 977
1970-04-20 04:38:38 113 William
1971-01-20 23:10:26 75 Whose
1971-07-01 12:46:13 352 dearest
1971-01-31 17:01:34 220 William
1970-06-09 20:38:52 148 rooms
1971-08-08 07:42:10 146
1970-01-28 15:17:41 903 find
...............etc
作为utdemir答案的一个变体,如果错误值非常罕见,那么您可以优化常见情况:
>>> values = ["12", "a", "bcd", "2.2"]
>>> types = [int, int, str, float]
>>> defaults = {int: 0, float: 0.0}
>>> try: res = [f(v) for v,f in zip(values,types)]
... except:
... res = []
... for v, f in zip(values, types):
... try:
... res.append(f(v))
... except ValueError:
... res.append(defaults[f])
即,首先尝试转换整条线路,假设不会出现任何问题。如果出现任何错误,请返回并一次转换一个值,修复所有错误值。感谢所有这些方法。是的,我几乎尝试了所有提到的方法,但没有一种表现得很好 我尝试了以下方法,它非常适合我的性能需求。这就是我所做的
[i]=如果值为,则为值!=''其他0
def强制(l):
返回[l[0],int(l[1]),int(l[2])…]
你知道你想要的类型映射吗?i、 e.您是否总是知道
tlist[0]
应该是datetime
,等等?是的,我知道类型的映射。您是从数据库获取值的吗?我从simpledb读取这些值,simpledb以纯CSV格式存储这些值。所以当我读取值时,我会得到CSV值。我将这些CSV值转换为单独的列表,然后任务是将其转换为上面提到的内容。error\u data
需要多长时间?如果它很长,将其转换为集
会加快速度。我在发布答案后立即看到了你的评论,并相应地进行了更新。我喜欢使用try/except。由于问题是要求优化,我将使用itertools.izip
而不是zip
。这是如何处理日期时间转换的?这看起来是正确的方法,我将立即尝试并让大家知道。谢谢。@utdemir定义了另一个问题(out是datetime字符串),这使得它很容易解决。显然,从异常中恢复需要很大的性能损失。我仍然在测试我的代码——仍然在按照您的建议实现代码之后,它需要更多的时间来运行。我会让每个人都知道我的发现。。这里的问题是如何将所有这些值转换为各自的类型。。。实际代码是非常复杂的数据收集框架的一部分,因此我无法复制/粘贴它。我只想写代码的相关部分,描述问题。
>>> values = ["12", "a", "bcd", "2.2"]
>>> types = [int, int, str, float]
>>> defaults = {int: 0, float: 0.0}
>>> try: res = [f(v) for v,f in zip(values,types)]
... except:
... res = []
... for v, f in zip(values, types):
... try:
... res.append(f(v))
... except ValueError:
... res.append(defaults[f])