2013-07-07 4 views
12

У меня есть программа, в которой я в основном настраиваю вероятность того, что некоторые вещи произойдут на основе того, что уже известно. Мой файл данных уже сохранен как объект рассола Словаря в Dictionary.txt. Проблема в том, что каждый раз, когда я запускаю программу, которую он втягивает в Dictionary.txt, превращает его в объект словаря, делает его редактированием и перезаписывает Dictionary.txt. Это довольно интенсивный объем памяти, так как Dictionary.txt составляет 123 МБ. Когда я дамп я получаю MemoryError, кажется, все в порядке, когда я тяну его в ..Pickle dump огромный файл без ошибки памяти

  • Есть ли лучший (более эффективный) способ делать изменения? (Возможно, без необходимости переписывать весь файл каждый раз)

  • Есть ли способ, которым я могу вызвать сбор мусора (через модуль gc)? (У меня уже есть автоматическое включение через gc.enable())

  • Я знаю, что помимо readlines() вы можете читать строки за строкой. Есть ли способ редактировать словарь поэтапно по строкам, когда у меня уже есть полностью заполненный файл объекта словаря в программе.

  • Любые другие решения?

Благодарим за ваше время.

+0

Есть несколько сжимающих и других библиотек. Лично мне нравится укроп и H5Py для больших объектов. Если вы используете scikit learn и должны использовать базовую модель в словаре, возможно, вы также можете использовать joblib (только для этих моделей). –

ответ

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() 
+0

Также в стандартной библиотеке находится модуль [shelve] (https://docs.python.org/2/library/shelve.html#module-shelve), который позволяет нам открыть «полкульный» диктофонный объект, который использует 'anydbm' снизу для хранения произвольных разборных объектов в качестве значений (ключи все еще являются строками). Таким образом, травление и рассыпание происходит при зернистости ценностей. По умолчанию полка сохраняет значения на диске всякий раз, когда мы назначаем один из его ключей. –

2

Вы пробовали использовать потоковый рассол: https://code.google.com/p/streaming-pickle/

Я просто решить подобную ошибку памяти, переключаясь на потоковый рассол.

+0

потоковый расчесок не подходит для настоящего случая всего одного словарного объекта. Когда он лучше подходит (например, для огромного списка), нормальный рассол также может сделать трюк, потому что вы можете сбрасывать несколько соленья в один и тот же файл один за другим, см. Вопрос [«Сохранение и загрузка нескольких объектов в файле пиреней python "] (http://stackoverflow.com/questions/20716812/saving-and-loading-multiple-objects-in-python-pickle-file/28745948) –

1

Как насчет этого?

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 
+0

Я пробовал это, и он мариновался успешно, но я получаю" ValueError: небезопасная строка pickle'-error, когда я пытаюсь раскрыть ее с помощью pickle.load (open ("temp.p", "rb")). Я читал, что это может быть из-за не закрывания рассола, но экземпляр Pickler не имеет атрибута «close». Не могли бы вы помочь мне узнать, как снова распечатать файл? – ROIMaison

+0

может быть, что файловый объект никогда не закрывается? –

1

У меня была ошибка памяти и решить ее с помощью протокола = 2:

cPickle.dump(obj, file, protocol=2)

1

Недавно я имел эту проблему. Попробовав cpickle с ASCII и бинарным протоколом 2, я обнаружил, что мой SVM из sci-kit, обученный на 20+ gb данных, не травил из-за ошибки памяти. Тем не менее, пакет укропа, похоже, решил проблему. Dill не будет создавать много улучшений для словаря, но может помочь в потоковой передаче. Он предназначен для потока маринованных байтов по сети.

import dill 

with open(path,'wb') as fp: 
    dill.dump(outpath,fp) 
    dill.load(fp) 

Если эффективность является проблемой, попробуйте загрузить/сохранить в базу данных. В этом случае решение для хранения данных может быть проблемой. На 123 МБ панды должны быть в порядке. Однако, если машина имеет ограниченную память, SQL предлагает быстрые, оптимизированные операции с мешками над данными, обычно с поддержкой многопоточности. Мое ядро ​​svm сохранено.

8

Я являюсь автором пакета под названием 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

+0

Для будущих читателей: вы можете вызвать 'd.dump(); d.clear(); gc.collect() 'между каждым присваиванием массива numpy на' d'. Это гарантирует, что за один раз в памяти будет только один массив numpy, полезный, если массивы достаточно велики для размещения в памяти (например, у меня). –

+0

Что произойдет, если у вас есть существующий словарь, который вы хотите сохранить на диск? Например, если я выполняю 'для ключа в mydict: d [key] = mydict [key]', скопирует ли он данные или просто держит ссылку на него? –

+0

Если у вас есть существующий dict, вы можете передать его в новый архив 'klepto' с ключевым словом' dict'. Я считаю, что он не должен делать копию. –

1

Ни один из вышеперечисленных ответов не работает для меня. Я закончил с использованием Hickle, который является заменой для рассола на основе HDF5. Вместо того, чтобы сохранять его в рассол, он сохраняет данные в файл HDF5. 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') 
+2

Не подходит для python 3.5 – omarflorez

1

у меня был тот же вопрос. Я использую 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) 
1

Это может показаться тривиальным, но попытаться использовать 64-разрядные Python, если вы не ,