从文件中读取数字列表的最快方法

问题描述:

我在Stack Overflow中发现了一些类似的问题,但我相信我可以从特定于我的案例的建议中受益。从文件中读取数字列表的最快方法

我必须在一个文件中存储大约8万个实值数字列表,并在稍后读取它们。

首先,我想cPickle,但阅读时间没有吸引力:

>>> stmt = """ 
with open('pickled-data.dat') as f: 
    data = cPickle.load(f) 
""" 
>>> timeit.timeit(stmt, 'import cPickle', number=1) 
3.8195440769195557 

后来我发现,存储数字作为明文允许更快的读取(有道理的,因为cPickle必须担心很多东西):

>>> stmt = """ 
data = [] 
with open('text-data.dat') as f: 
    for line in f: 
     data.append([float(x) for x in line.split()]) 
""" 
>>> timeit.timeit(stmt, number=1) 
1.712096929550171 

这是一个很好的改善,但我认为我仍然可以优化它在某种程度上,因为其他语言编写的程序可以从文件中显着更快的读取类似的数据。

任何想法?

+1

如果你存储这么多的列表,sqlite数据库是不是一个更好的数据结构? – BrtH 2012-08-02 14:28:13

+0

您是否尝试过'csv'模块的阅读器?它会避免你所调用的手动分割。 – jmetz 2012-08-02 14:28:56

+1

@BrtH数据库看起来像是一种矫枉过正,我只需要加载所有这些列表。 – erickrf 2012-08-02 15:46:39

如果numpy的阵列是可行的,numpy.fromfile将可能是读取文件(这里有一个somewhat related question我问只是一对夫妇日前)

或者,好像你的表现会更好一点与struct最快的选项,尽管我还没有测试过它:

import struct 
def write_data(f,data): 
    f.write(struct.pack('i',len())) 
    for lst in data: 
     f.write(struct.pack('i%df'%len(lst),len(lst),*lst)) 

def read_data(f): 
    def read_record(f): 
     nelem = struct.unpack('i',f.read(4))[0] 
     return list(struct.unpack('%df'%nelem,f.read(nelem*4))) #if tuples are Ok, remove the `list`. 

    nrec = struct.unpack('i',f.read(4))[0] 
    return [ read_record(f) for i in range(nrec) ] 

这假定将数据存储为4字节的浮点数就足够了。如果您想要一个真正的双精度数字,请将格式语句从f更改为d并将nelem*4更改为nelem*8。这里可能存在一些次要的可移植性问题(例如,数据类型的字节顺序和sizeof)。

+0

我怀疑numpy fromfile是相对优化的,可能是比结构,情况允许更好的解决方案。 – jmetz 2012-08-02 14:38:01

+0

@mutzmatron - 是的,可能 - 虽然真的不应该有太大的差异。我敢打赌,他们几乎完成同样的事情 - numpy的优点是它可以将对象放入顺序存储器中(本质上只需要分配1块和1个指针来操作指针)。另一方面struct可能仍然只分配一个块,但它也需要一个读取每个浮点的指针,所以这是一个额外的工作。无论哪种方式,我希望它比读取ASCII文本更快,将其转换为浮动(全部在非类型化的python框架内完成)。 – mgilson 2012-08-02 14:41:14

+0

谢谢,'numpy.fromfile'耗时0.02秒。 – erickrf 2012-08-02 16:04:06