加速文件解析
下面这个函数的作用是把一个CSV文件解析成一个字典列表。这个列表里的每个元素都是一个字典,字典里的值是根据文件的表头来索引的(假设表头在第一行)。
不过,这个函数运行得非常慢,对于一个相对小的文件(少于30,000行),大约需要6秒钟才能完成。
我该怎么加快速度呢?
def csv2dictlist_raw(filename, delimiter='\t'):
f = open(filename)
header_line = f.readline().strip()
header_fields = header_line.split(delimiter)
dictlist = []
# convert data to list of dictionaries
for line in f:
values = map(tryEval, line.strip().split(delimiter))
dictline = dict(zip(header_fields, values))
dictlist.append(dictline)
return (dictlist, header_fields)
针对评论的回复:
我知道有一个csv模块,我可以这样使用它:
data = csv.DictReader(my_csvfile, delimiter=delimiter)
这样速度快多了。但是,问题是它不会自动把明显是浮点数和整数的内容转换成数字,而是把它们当成字符串。那我该怎么解决这个问题呢?
使用“Sniffer”类对我来说不太管用。当我在我的文件上尝试时,出现了这个错误:
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/csv.py", line 180, in sniff
raise Error, "Could not determine delimiter"
Error: Could not determine delimiter
我该怎么让DictReader在明显的情况下把字段解析成它们的类型呢?
谢谢。
谢谢。
3 个回答
那 pandas 呢?
import pandas as pd
# load everything in
df = pd.read_table(filename)
# coerce strings to numeric
df = df.convert_objects(convert_numeric=True)
我看到你的代码有几个问题:
你为什么需要用字典?每个字典实例都存储了键,这样会占用很多内存。
你真的需要把所有实例都放在内存里吗?用
yield
可能是个不错的选择。试图转换每个值会浪费时间,而且在我看来没有必要。如果你有一列的值是“abc”和“123”,那么最后一个值应该是字符串。所以一列的类型应该是固定的,转换应该明确进行。
即使你想用自己的转换逻辑,也可以使用 csv 模块,然后再进行值的转换。
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。比如说,当你在写代码时,可能会发现某个功能没有按照预期工作。这种情况可能是因为你没有正确使用这个工具,或者是因为你的代码中有一些小错误。
为了找到问题所在,通常我们会查看错误信息。这些信息就像是程序给我们的提示,告诉我们哪里出了问题。理解这些错误信息是解决问题的第一步。
此外,很多时候我们可以在网上找到其他人遇到类似问题的讨论,比如在StackOverflow这样的论坛上。这里有很多开发者分享他们的经验和解决方案,你可以从中获得灵感,找到解决自己问题的方法。
总之,遇到问题时不要慌张,先仔细查看错误信息,然后可以去网上查找相关的讨论和解决方案,这样你就能更快地解决问题了。
import ast
# find field types
for row in csv.DictReader(my_csvfile, delimiter=delimiter):
break
else:
assert 0, "no rows to process"
cast = {}
for k, v in row.iteritems():
for f in (int, float, ast.literal_eval):
try:
f(v)
cast[k] = f
break
except (ValueError, SyntaxError):
pass
else: # no suitable conversion
cast[k] = lambda x: x.decode(encoding)
# read data
my_csvfile.seek(0)
data = [dict((k.decode(encoding), cast[k](v)) for k, v in row.iteritems())
for row in csv.DictReader(my_csvfile, delimiter=delimiter)]