我有一个程序,我基本上根据已知的事情调整某些事情发生的概率。我的数据文件已经保存为Dictionary.txt中的pickle Dictionary对象。问题是,每次运行程序时它都会拉入Dictionary.txt,将其转换为字典对象,进行编辑并覆盖Dictionary.txt。这是相当大的内存密集型,因为Dictionary.txt是123 MB。当我转储我得到MemoryError时,当我把它拉进来时,一切似乎都很好。
是否有更好(更有效)的编辑方式? (或许不必每次都覆盖整个文件)
有没有办法可以调用垃圾收集(通过gc模块)? (我已经通过gc.enable())自动启用了它
我知道除了readlines()之外你还可以逐行阅读。当我在程序中已经有一个完整的Dictionary对象文件时,有没有办法逐行逐行编辑字典。
还有其他解决方案吗?
感谢您的时间。
答案 0 :(得分:12)
我是名为klepto
的软件包的作者(也是dill
的作者)。
klepto
用于以非常简单的方式存储和检索对象,并为数据库,内存缓存和磁盘上的存储提供简单的字典界面。下面,我展示了将大对象存储在"目录存档"中,这是一个文件系统目录,每个条目有一个文件。我选择序列化对象(速度较慢,但使用dill
,因此您可以存储几乎所有对象),并选择缓存。使用内存缓存使我能够快速访问目录存档,而无需将整个存档存储在内存中。与数据库或文件交互可能很慢,但与内存交互很快......您可以根据需要从存档中填充内存缓存。
>>> import klepto
>>> d = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> d
dir_archive('stuff', {}, cached=True)
>>> import numpy
>>> # add three entries to the memory cache
>>> d['big1'] = numpy.arange(1000)
>>> d['big2'] = numpy.arange(1000)
>>> d['big3'] = numpy.arange(1000)
>>> # dump from memory cache to the on-disk archive
>>> d.dump()
>>> # clear the memory cache
>>> d.clear()
>>> d
dir_archive('stuff', {}, cached=True)
>>> # only load one entry to the cache from the archive
>>> d.load('big1')
>>> d['big1'][-3:]
array([997, 998, 999])
>>>
klepto
提供对大量存储的快速灵活访问,如果存档允许并行访问(例如某些数据库),那么您可以并行读取结果。在不同的并行流程或不同的机器上共享结果也很容易。在这里,我创建了第二个存档实例,指向同一个目录存档。在两个对象之间传递密钥很容易,并且与不同的进程没有区别。
>>> f = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> f
dir_archive('stuff', {}, cached=True)
>>> # add some small objects to the first cache
>>> d['small1'] = lambda x:x**2
>>> d['small2'] = (1,2,3)
>>> # dump the objects to the archive
>>> d.dump()
>>> # load one of the small objects to the second cache
>>> f.load('small2')
>>> f
dir_archive('stuff', {'small2': (1, 2, 3)}, cached=True)
您还可以从各种级别的文件压缩中选择,以及是否 您希望文件是内存映射的。有很多不同 选项,包括文件后端和数据库后端。界面 但是,它是相同的。
关于有关垃圾收集和编辑字典部分的其他问题,两者都可以使用klepto
,因为您可以单独加载和删除内存缓存中的对象,转储,加载和同步存档后端,或任何其他字典方法。
请在此处查看更长的教程:https://github.com/mmckerns/tlkklp
在此处获取klepto
:https://github.com/uqfoundation
答案 1 :(得分:9)
我遇到了同样的问题。我使用joblib并完成了工作。如果有人想知道其他可能性。
将模型保存到磁盘
from sklearn.externals import joblib
filename = 'finalized_model.sav'
joblib.dump(model, filename)
一段时间后......从磁盘加载模型
loaded_model = joblib.load(filename)
result = loaded_model.score(X_test, Y_test)
print(result)
答案 2 :(得分:3)
我有内存错误并使用protocol = 2解决了它:
cPickle.dump(obj, file, protocol=2)
答案 3 :(得分:2)
如果您的键和值是字符串,则可以使用Python标准库中提供的嵌入式持久键值存储引擎之一。 anydbm
模块文档中的示例:
import anydbm
# Open database, creating it if necessary.
db = anydbm.open('cache', 'c')
# Record some values
db['www.python.org'] = 'Python Website'
db['www.cnn.com'] = 'Cable News Network'
# Loop through contents. Other dictionary methods
# such as .keys(), .values() also work.
for k, v in db.iteritems():
print k, '\t', v
# Storing a non-string key or value will raise an exception (most
# likely a TypeError).
db['www.yahoo.com'] = 4
# Close when done.
db.close()
答案 4 :(得分:2)
您是否尝试使用流式传感器:https://code.google.com/p/streaming-pickle/
我刚刚通过切换到流式泡菜解决了类似的内存错误。
答案 5 :(得分:2)
这个怎么样?
import cPickle as pickle
p = pickle.Pickler(open("temp.p","wb"))
p.fast = True
p.dump(d) # d could be your dictionary or any file
答案 6 :(得分:1)
我最近遇到了这个问题。在尝试使用ASCII和二进制协议2进行cpickle之后,我发现我的sci-kit中的SVM学习了20+ gb数据,因为内存错误而没有进行酸洗。然而,莳萝包似乎解决了这个问题。 Dill不会为字典创建许多改进,但可能有助于流式传输。它旨在通过网络流式传输腌制字节。
import dill
with open(path,'wb') as fp:
dill.dump(outpath,fp)
dill.load(fp)
如果效率问题,请尝试加载/保存到数据库。在这种情况下,您的存储解决方案可能是一个问题。在1200 MB的熊猫应该没事。但是,如果机器内存有限,SQL提供快速,优化的数据包操作,通常具有多线程支持。 我的poly kernel svm已保存。
答案 7 :(得分:1)
上述答案都不适合我。我最终使用了Hickle,它是基于HDF5的泡菜的替代品。它将数据保存到HDF5文件,而不是将其保存到pickle。对于大多数用例而言,API是相同的,并且它具有一些非常酷的功能,例如压缩。
pip install hickle
示例:
# Create a numpy array of data
array_obj = np.ones(32768, dtype='float32')
# Dump to file
hkl.dump(array_obj, 'test.hkl', mode='w')
# Load data
array_hkl = hkl.load('test.hkl')
答案 8 :(得分:1)
这看起来似乎微不足道,但如果不是,请尝试使用64位Python。