csvlike-fi的快速解析

2024-06-28 20:10:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要读入的文件类型具有以下结构:一行标题,然后用制表符逐行分隔条目,如下所示:

Date    Timestamp    Identifier    Value

文件大小约为2MB,每个标识符中约有200个值(约600k行)。可以使用pythons csv reader读入此文件并提取所需的标识符列。因为我有好几组这样的文件,读入感觉很慢:

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]   

这是可行的,但不是真的更快。我还能做些什么?你知道吗


Tags: 文件csvimportredata标识符resultreader
2条回答

我也有类似的要求

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)

现在尝试计时,对于大小为52MB(64列,60897行)的文本文件,获取所需行需要不到3秒的时间。结果有308行。你知道吗

请注意,我的文件是用逗号分隔的,所以用逗号分隔。另外,我使用的是一台8GB内存的windows7机器。你知道吗

另外,你能分享一下你的代码的性能细节吗。我很想知道我今后应该采取哪种方法。你知道吗

简短回答:

csv readerharaprasadj(见下面的答案)在速度上几乎相同。你知道吗

长答案:

我尝试了所有建议的方法,即haraprasadj建议的numpy.genfromtxt()代码,并对我的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秒
  • haraprasadj:1.033秒
  • readfile:1.081秒

虽然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_file1kword=1.1s 3kword=1.1s
  • haraprasadj1kword=1.0s 3kword=1.1s
  • power_read1字=1.4s 3字=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秒
  • haraprasadj1.06秒

与以前的结果相比,排版只需要很少的时间,这让我很惊讶。
剩下的区别是haraprasadj占用更多内存,这对于某些应用程序可能很重要。为了可读性,我现在将使用我原来的read\u file(),并开始研究并行计算。你知道吗

相关问题 更多 >