2010-08-03 3 views
4

У меня есть программа Python, которая обрабатывает довольно большие массивы NumPy (в сотнях мегабайт), которые хранятся на диске в файлах pickle (один массив размером ~ 100 МБ на файл). Когда я хочу запустить запрос по данным, я загружаю весь массив, используя pickle, а затем выполняю запрос (так что с точки зрения программы Python весь массив находится в памяти, даже если ОС заменяет его) , Я сделал это главным образом потому, что считал, что возможность использования векторизованных операций в массивах NumPy будет значительно быстрее, чем использование циклов для каждого элемента.Lazy Evaluation для итерации через массивы NumPy

Я запускаю это на веб-сервере с ограничениями памяти, с которыми я быстро сталкиваюсь. У меня есть много разных запросов, которые я запускаю на данных, поэтому запись кода «chunking», который загружает части данных из отдельных файлов pickle, обрабатывает их, а затем переходит к следующему фрагменту, скорее всего, добавит много сложности. Конечно, было бы предпочтительнее сделать этот «chunking» прозрачным для любой функции, которая обрабатывает эти большие массивы.

Похоже, что идеальным решением было бы нечто вроде генератора, который периодически загружал блок данных с диска и затем передавал значения массива один за другим. Это существенно сократит объем памяти, требуемый программой, не требуя дополнительной работы со стороны отдельных функций запроса. Можно ли сделать что-то подобное?

+0

Может быть полезная ссылка: только что выяснилось, что это называется «внеочередной» задачей. – erich

ответ

9

PyTables является пакет для управления иерархические наборы данных. Он предназначен для решения этой проблемы для вас. Структура

2

Похоже, идеальным решением было бы что-то вроде генератора, который периодически загружен блок из данных с диска, а затем прошли массив значений из одного за другим. Этот существенно уменьшил бы сумму памяти, требуемую программой без дополнительной работы над частью индивидуального запроса . Можно ли сделать что-то вроде этого?

Да, но не путем хранения массивов на диске в одном рассоле - протокол рассола просто не предназначен для «постепенной десериализации».

Вы можете написать несколько рассолы в тот же самый открытый файл, один за другим (используйте dump, неdumps), а затем «ленивым оценщик для итерации» просто нужно использовать pickle.load каждый раз.

Пример кода (Python 3.1 - в 2.Any вы хотите cPickle вместо pickle и -1 для протокола, и т.д., конечно ;-):

>>> import pickle 
>>> lol = [range(i) for i in range(5)] 
>>> fp = open('/tmp/bah.dat', 'wb') 
>>> for subl in lol: pickle.dump(subl, fp) 
... 
>>> fp.close() 
>>> fp = open('/tmp/bah.dat', 'rb') 
>>> def lazy(fp): 
... while True: 
...  try: yield pickle.load(fp) 
...  except EOFError: break 
... 
>>> list(lazy(fp)) 
[range(0, 0), range(0, 1), range(0, 2), range(0, 3), range(0, 4)] 
>>> fp.close() 
4

Numpy в памяти отображенных данных (memmap) может быть хорошим выбором здесь.

Вы получаете доступ к массивам NumPy из двоичного файла на диске, не загружая сразу весь файл в память.

(Обратите внимание, я верю, но я не уверен, что Numpys memmap объект не таких же, как питоны - в частности, NumPys является массивом типа, Python является файлом типа.)

метод подписи:

A = NP.memmap(filename, dtype, mode, shape, order='C') 

Все аргументы являются прямыми (то есть, они имеют тот же смысл, что и используется в других местах в NumPy) для «порядка», который относится к порядку ndarray размещения памяти, за исключением. Я считаю, что по умолчанию это «C», а (только) другой вариант - «F», для Fortran - как и в других местах, эти два параметра представляют собой порядок строк и столбцов, соответственно.

Эти два метода являются:

вровень (который записывает на диск любые изменения, внесенные в массив); и

близко (который записывает данные в массив memmap, а точнее к массиву типа памяти-карты с данными, хранящимися на диске)

Пример использования:

import numpy as NP 
from tempfile import mkdtemp 
import os.path as PH 

my_data = NP.random.randint(10, 100, 10000).reshape(1000, 10) 
my_data = NP.array(my_data, dtype="float") 

fname = PH.join(mkdtemp(), 'tempfile.dat') 

mm_obj = NP.memmap(fname, dtype="float32", mode="w+", shape=1000, 10) 

# now write the data to the memmap array: 
mm_obj[:] = data[:] 

# reload the memmap: 
mm_obj = NP.memmap(fname, dtype="float32", mode="r", shape=(1000, 10)) 

# verify that it's there!: 
print(mm_obj[:20,:]) 
+0

Это действительно удобно, если вы не хотите идти навстречу установке PyTables. – erich

Смежные вопросы