Python 2.7中保存/加载大型列表的最快方法是什么?

10
什么是在Python 2.7中保存/加载大型列表的最快方法?如果这已经被问过了,我很抱歉,但当我搜索时找不到确切的答案...更具体地说,我正在测试模拟某种东西的方法,并且需要将每个测试的结果与精确解进行比较。我有一个Python脚本,可以生成表示精确解的值列表,我不想每次运行新模拟时都重新计算它。因此,我想将其保存在某个位置,并只需加载解决方案,而不是每次想查看模拟结果有多好时都重新计算它。我也不需要保存的文件可读。我只需要能够在Python中加载它。

1
你可以使用pickle(https://docs.python.org/2/library/pickle.html),numpy.dump或者http://docs.scipy.org/doc/numpy/reference/generated/numpy.save.html来处理numpy数组。 - Padraic Cunningham
@PadraicCunningham 嗯,好的谢谢!你知道这些方法中有哪个比另一个明显更快吗?我还想知道,如果我将代码修改为以numpy数组格式而不是列表格式生成参考解决方案,它是否会加速或减慢代码。 - nukeguy
如果你担心性能问题,也许你应该使用numpy来完成所有的工作。 - Padraic Cunningham
我对生成解决方案的部分并不太担心,因为那只会发生一次。重点是加载部分需要多次进行。我在想,加载numpy数组是否比列表更快? - nukeguy
绝对的,加载一个numpy数组比解封一个列表更快。 - shx2
4个回答

10
使用 np.load 和 tolist 比任何其他解决方案都要快得多:
In [77]: outfile = open("test.pkl","w")   
In [78]: l = list(range(1000000))   

In [79]:  timeit np.save("test",l)
10 loops, best of 3: 122 ms per loop

In [80]:  timeit np.load("test.npy").tolist()
10 loops, best of 3: 20.9 ms per loop

In [81]: timeit pickle.load(outfile)
1 loops, best of 3: 1.86 s per loop

In [82]: outfile = open("test.pkl","r")

In [83]: timeit pickle.load(outfile)
1 loops, best of 3: 1.88 s per loop

In [84]: cPickle.dump(l,outfile)
....: 
1 loops, best of 3: 
273 ms per loop    
In [85]: outfile = open("test.pkl","r")
In [72]: %%timeit
cPickle.load(outfile)
   ....: 
1 loops, best of 3: 
539 ms per loop

如果您使用numpy数组,Python 3中的numpy效率要高得多:

In [24]: %%timeit                  
out = open("test.pkl","wb")
pickle.dump(l, out)
   ....: 
10 loops, best of 3: 27.3 ms per loop

In [25]: %%timeit
out = open("test.pkl","rb")
pickle.load(out)
   ....: 
10 loops, best of 3: 52.2 ms per loop

In [26]: timeit np.save("test",l)
10 loops, best of 3: 115 ms per loop

In [27]: timeit np.load("test.npy")
100 loops, best of 3: 2.35 ms per loop

如果您想要一个列表,调用tolist并使用np.load会更快:

In [29]: timeit np.load("test.npy").tolist()
10 loops, best of 3: 37 ms per loop

1
这是使用 pickle 还是 cPickle - NDevox
1
似乎与此相当:https://dev59.com/_mQn5IYBdhLWcg3wcWvM 如果是这种情况,那么我可能建议如果他们已经使用numpy,那么使用numpy,如果他们没有使用,则使用cPickle。-但这似乎只是个人偏好。 - NDevox
在我的情况下,NumPy 的速度与 cPickle 相似。 pk.dump( a, open('a.pickle', 'wb'), pk.HIGHEST_PROTOCOL) - Potemkin

3
如PadraicCunningham所提到的,您可以对列表进行序列化处理。
import pickle

lst = [1,2,3,4,5]

with open('file.pkl', 'wb') as pickle_file:
    pickle.dump(lst, pickle_file, protocol=pickle.HIGHEST_PROTOCOL)

这将列表加载到文件中。 要提取它:
import pickle

with open('file.pkl', 'rb') as pickle_load:
    lst = pickle.load(pickle_load)
print(lst) # prints [1,2,3,4,5]
HIGHEST_PROTOCOL位是可选的,但通常建议使用。协议定义了pickle如何序列化对象,较低的协议倾向于与旧版本的Python兼容。
值得注意的有两点:
还有cPickle模块 - 为了优化速度而编写的C语言编写的。你可以像上面一样使用它。
Pickle也被知道存在一些不安全性(有一些方法来操纵pickle如何反序列化一个对象,你可以将其操纵成让Python做更多或更少你想要的事情)。因此,在打开未知数据时不应使用此库。在极端情况下,你可以尝试使用更安全的版本,例如spicklehttps://github.com/ershov/sPickle 我还建议查看其他库,如jsonmarshall

谢谢您的回复。对于我来说,安全部分不应该是一个问题,因为只有我能够访问数据(除非我的计算机被黑客攻击或其他什么)。您知道cPickle是否可能是最快的解决方案吗? - nukeguy
1
我无法确定最快的解决方案,因为我还没有运行测试。但是由于cPickle是用C编写的,它将比大多数用Python编写的东西(您将使用的大多数库)快得多。所以我认为这是一个不错的选择。 - NDevox
1
@nukeguy,还值得一提的是,没有太多其他的方法可以存储纯粹的Python对象而不将它们转换为可处理的格式。使用pickle/cPickle意味着您无需进行任何操作或解析,只需保存即可。所有这些显然将影响处理时间。 - NDevox

1

我对许多方法进行了分析(除了numpy方法),在简单数据集上,pickle / cPickle非常慢。最快的方式取决于您要保存的数据类型。如果您要保存字符串和/或整数列表,则我看到的最快的方法是使用for循环和','.join(...)将其直接写入文件;使用类似的for循环和.split(',')读取它。


0

您可能想要了解Python对象序列化,picklecPickle
http://pymotw.com/2/pickle/

pickle.dumps(obj[, protocol]) 如果省略protocol参数,则使用协议0。如果将protocol指定为负值或HIGHEST_PROTOCOL,则将使用最高协议版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接