我需要读入的文件类型具有以下结构:一行标题,然后逐行分隔条目,如下所示:
Date Timestamp Identifier Value
文件大小约为2MB,每个标识符大约有200个值(大约600k行)。可以使用pythons csv reader读取此文件并提取所需的Identifier列。由于我有几组这些文件,读入感觉很慢:
import csv
def read_file(fhandle, identifiers):
#identifiers = [identifier1, identifier2, ...]
#dialect from csvr.sniffer()
csvr = csv.reader(fhandle, dialect)
data = []
EOF = False
while not EOF:
try:
row=csvr.next()
if row[2] in identifiers:
data.append(tuple(row[1:]))
except StopIteration:
EOF = True
fhandle.close()
sorted(data, keyfunc) #keyfunc = lambda x: (x[1],x[0])
return data
我开始尝试使用此功能加速它(目前只读取一个标识符进行测试)。它使用正则表达式,以便只解析包含所需信息的行。它还添加到一个数组而不是附加到一个列表,我发现它在过去更快(对于大型数据集)。
import re
import numpy as np
def power_read(fhandle, identifier):
findme = '(?<=%s\W)[0-9.]+' %identifier
m = re.compile(findme)
result = np.zeros(10000)
cnt = 0
EOF = False
while not EOF:
try:
ln = fhandle.next()
found = re.search(m, ln)
if found:
result[cnt] = float(found.group(0))
cnt += 1
except StopIteration:
EOF=True
fhandle.close()
return result[0:cnt]
这样可行,但速度并不快。我还能调整什么呢?
答案 0 :(得分:1)
有类似的要求,我做了类似的事情:
data = [line.strip('\n').split(',') for line in open('test.txt','r').readlines()]
identifiers = ['2069784', '2640650']
filteredData = filter(lambda x:x[2] in identifiers, data)
现在尝试计时,对于大小为52 MB(64列,60897行)的文本文件,需要3秒钟才能获取所需的行。结果有308行。
请注意我的文件以逗号分隔,所以用逗号分隔。我还使用带有8GB RAM的Windows 7机器。
此外,您能否分享您的代码的效果详情。我很想知道我应该采取哪种方法。
答案 1 :(得分:0)
简短回答:
csv reader
和haraprasadj
(见下面的答案)速度几乎相同。
答案很长:
我尝试了所有建议的方法,numpy.genfromtxt()
,代码haraprasadj建议,我修改了我的power_read()
函数,如下所示:
def power_read(fhandle, identifiers):
findme = '(?<=%s\W)[0-9.]+' %identifiers[0]
result = np.zeros(10000)
cnt = 0
ALL = fhandle.read()
fhandle.close()
found = re.findall(findme, ALL, flags=re.S)
for f in found:
result[cnt] = float(f)
return result[0:cnt]
为什么要改变?我想出来,这种明智的调查显然需要更长的时间。问题版本是18次合并10次,而上述版本只有6次。
numpy.genfromtxt(fhandle, delimiter='\t',
dtype={'names':('Time', 'Identifier', 'Value'),
'formats':('datetime64[ns]', 'S50', 'f8')})
在同一设置中使用约41秒并取消其自身资格。
接下来,我评估了平均超过50次运行,结果如下:
power_read
:0.582 s haraprasadj
:1.033 s readfile
:1.081 s 虽然此时re
解决方案看起来像赢家,但它仍然不会立即读出多个标识符。此外,csv已经读取时间戳。我现在将研究如何处理几个关键字以及它如何影响执行时间。此外,完整阅读必须始终牢记内存限制。
使用power_read()
函数的下一步是,我添加了一些更多功能,包括时间戳提取和多个关键字的支持,返回一个方便的字典:
def power_read(fhandle, identifiers):
ALL = fhandle.read()
fhandle.close()
result = {}
for i in identifiers:
findme = ('(?P<timestamp>\d+-\d+-\d+ \d+:\d+:\d+.[\d\+]+)\W%s\W(?P<value>[\d.]+)' %i)
res = np.empty(shape=(10000, 2), dtype=[('time','datetime64[ns]'), ('value','f4')])
cnt = 0
found = re.findall(findme, ALL, flags=re.S)
for f in found:
res[cnt] = np.array(f, dtype=[('time','datetime64[ns]'), ('value','f4')])
result[i] = res[0:cnt,:]
return result
我测试了1个关键字和3个关键字:
read_file
1kword = 1.1s 3kword = 1.1s haraprasadj
1kword = 1.0s 3kword = 1.1s power_read
1kword = 1.4s 3kword = 4.2s 总结一下,除非一个人只想提取一个值csv阅读器和haraprasadj的方法看起来更优越。尽管如此,前两种方法还没有发生类型转换。有人如何有效地对结果进行类型转换?为了调查,我更改了以下方法,并使用三个关键字进行调用:
def read_file(fhandle, identifiers, dialect):
csvr = csv.reader(fhandle, dialect)
data = []
EOF = False
while not EOF:
try:
row=csvr.next()
if row[2] in identifiers:
data.append(tuple(row[1:-1]))
except StopIteration:
EOF = True
fhandle.close()
data = np.array(data, dtype=None)
time = data[:,0]
ids = data[:,1]
value = data[:,2]
res = {}
for i in identifiers:
msk = np.where(ids==i, True, False)
res[i] = np.array(zip(time[msk], value[msk]), dtype=[('time','datetime64[us]'), ('value','f8')])
return res
和第二个函数,针对我处理的确切数据进行了优化:
def haraprasadj(fhandle, identifiers):
data = [line.strip().split('\t')[1:] for line in fhandle.readlines()]
fhandle.close()
result = np.array(filter(lambda x:x[1] in identifiers, data))
time =result[:,0]
ids = result[:,1]
value = result[:,2]
res = {}
for i in identifiers:
msk = np.where(ids==i, True, False)
res[i] = np.array(zip(time[msk], value[msk]), dtype=[('time','datetime64[us]'), ('value','f8')])
return res
事实证明,两种方法的速度大致相同(至少对于我的测试文件大小):
read_file()
1.12 s haraprasadj
1.06 s 与之前的结果比较表明,类型转换只需要很短的时间,这对我来说是令人惊讶的。
剩下的区别是haraprasadj
需要更多内存,这对某些应用程序可能很重要。为了便于阅读,我将使用我原来的read_file(),现在开始研究并行计算。