在Python中将numpy数组写入文件的有效方法

时间:2018-07-17 23:58:36

标签: python numpy

我处理的数据约为600万,并且需要大量时间才能写入文件。我该如何改善呢?

以下是我尝试过的两种方法:

import numpy as np
import time
test_data = np.random.rand(6000000,12)
T1 = time.time()
np.savetxt('test',test_data, fmt='%.4f', delimiter=' ' )
T2 = time.time() 
print "Time:",T2-T1,"Sec"
file3=open('test2','w')
for i in range(6000000):
    for j in range(12):
        file3.write('%6.4f\t' % (test_data[i][j]))
    file3.write('\n')
T3 = time.time() 
print "Time:",T3-T2,"Sec" 

时间:56.6293179989秒

时间:115.468323946秒

我正在处理至少100个这样的文件,总时间很多,请帮忙。另外,我不是用.npy或压缩格式编写的,因为我需要在matlab中阅读它们并进行进一步处理。

3 个答案:

答案 0 :(得分:3)

您是否考虑过h5py

这是粗略的单次运行时间比较:

>>> import numpy as np
>>> import time
>>> import h5py
>>> test_data = np.random.rand(6000000,12)
>>> file = h5py.File('arrays.h5', 'w')

>>> %time file.create_dataset('test_data', data=test_data, dtype=data.dtype)
CPU times: user 1.28 ms, sys: 224 ms, total: 225 ms
Wall time: 280 ms
<HDF5 dataset "test_data": shape (6000000, 12), type "<f8">

>>> %time np.savetxt('test',test_data, fmt='%.4f', delimiter=' ' )
CPU times: user 24.4 s, sys: 617 ms, total: 25 s
Wall time: 26.3 s

>>> file.close()

答案 1 :(得分:1)

save几乎总是比savetxt快得多。它只是转储原始字节,而不必将其格式化为文本。它还写入较小的文件,这意味着更少的I / O。而且在加载时,您将获得同等的好处:更少的I / O,并且没有文本解析。

除了save的优点之外,以下所有其他内容基本上都是一个变体。而且,如果您查看末尾的时间,所有时间都在一个数量级内,但都比savetxt快两个数量级。因此,您可能只是对200:1的加速感到满意,而不在乎尝试进一步调整。但是,如果您确实需要进一步优化,请继续阅读。


savez_compressed使用DEFLATE压缩保存数组。这意味着您浪费了大量CPU,但节省了一些I / O。如果这是一个慢速的磁盘使您减速,那将是一个胜利。请注意,对于较小的数组,恒定的开销可能会比压缩加速所带来的损害更大,并且,如果您使用的是随机数组,则压缩的可能性很小甚至没有。

savez_compressed也是一个多数组保存。在这里这似乎没有必要,但是如果将一个巨大的数组分成20个较小的数组,则有时速度可能会大大加快。 (尽管我不确定为什么。)这样做的代价是,如果仅将load.npz ip stackzeros ip在一起,就不会获得连续的存储,因此如果那很重要,则必须编写更复杂的代码。

请注意,我下面的测试使用随机数组,因此压缩只是浪费了开销。但是,针对arangeIn [70]: test_data = np.random.rand(1000000,12) In [71]: %timeit np.savetxt('testfile', test_data) 9.95 s ± 222 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) In [72]: os.stat('testfile').st_size Out[74]: 300000000 进行的测试在相反的方向上会产生误导,因此…这是对真实数据进行测试的东西。

另外,我在具有相当快的SSD的计算机上,因此CPU和I / O之间的权衡可能不会像在运行的任何计算机上那样不平衡。


numpy.memmap或分配到stdlib mmap.mmap中的数组通过直写式高速缓存备份到磁盘。这不应减少总的I / O时间,但这意味着I / O不会在一次结束时一次全部发生,而是会分散到整个计算过程中-这通常意味着它可以与您的计算并行发生繁重的CPU工作。因此,您无需花费50分钟的计算再节省10分钟,而是花费55分钟的计算并保存。

很难用一种实际上不进行任何计算的程序来以任何明智的方式来测试该程序,因此我没有理会。


pickle或其替代之一,例如dillcloudpickle。确实没有充分的理由说明泡菜应该比原始数组转储更快,但有时似乎是这样。

对于像我测试中那样的简单连续数组,pickle只是与二进制转储完全相同的字节周围的一个小包装,因此只是纯开销。


为进行比较,下面是我测试每个人的方法:

%timeit

注意在那里使用timeit。如果您不使用IPython,请使用stdlib中的time模块来稍微做些相同的事情。使用timeit进行测试会遇到各种各样的问题(如savetxt文档中所述,但是最大的问题是您只做一个代表。对于基于I / O的基准测试,这尤其糟糕


下面是每个结果—但是,鉴于上述警告,您实际上应该只考虑前两个有意义。

  • save:9.95s,300MB
  • savez_compressed:45.8毫秒,96MB
  • pickle:360ms,90MB
  • {{1}}:287ms,96MB

答案 2 :(得分:0)

使用泡菜怎么样?我发现它更快。

import numpy as np
import time
import pickle
test_data = np.random.rand(1000000,12)

T1 = time.time()
np.savetxt('testfile',test_data, fmt='%.4f', delimiter=' ' )
T2 = time.time()
print ("Time:",T2-T1,"Sec")

file3=open('testfile','w')
for i in range(test_data.shape[0]):
    for j in range(test_data.shape[1]):
        file3.write('%6.4f\t' % (test_data[i][j]))
    file3.write('\n')
file3.close()
T3 = time.time()
print ("Time:",T3-T2,"Sec")

file3 = open('testfile','wb')
pickle.dump(test_data, file3)
file3.close()
T4 = time.time()
print ("Time:",T4-T3,"Sec")

# load data
file4 = open('testfile', 'rb')
obj = pickle.load(file4)
file4.close()
print(obj)

输出为

Time: 9.1367928981781 Sec
Time: 16.366491079330444 Sec
Time: 0.41736602783203125 Sec