PyTables: индексация нескольких измерений больших массивов

Я анализирую некоторые данные изображения, состоящие из больших трехмерных массивов интенсивности пикселей с размерами [frame, x, y]. Поскольку они обычно слишком велики для хранения в памяти, они размещаются на жестком диске в виде массивов PyTables.

Что я хотел бы сделать, так это считывать интенсивность в произвольном подмножестве пикселей во всех кадрах. Естественным способом сделать это кажется индексирование списка:

import numpy as np
import tables

tmph5 = tables.open_file('temp.hdf5', 'w')
bigarray = tmph5.create_array('/', 'bigarray', np.random.randn(1000, 200, 100))

roipixels = [[0, 1, 2, 4, 6], [34, 35, 36, 40, 41]]
roidata = bigarray[:, roipixels[0], roipixels[1]]
# IndexError: Only one selection list is allowed

К сожалению, кажется, что PyTables в настоящее время поддерживает только один набор индексов списка. Еще одна проблема заключается в том, что индекс списка не может содержать дубликаты — я не мог одновременно читать пиксели [1, 2] и [1, 3], так как мой список координат x пикселей содержал бы [1, 1]. Я знаю, что могу перебирать строки в массиве:

roidata = np.asarray([row[roipixels[0], roipixels[1]] for row in bigarray])

но эти итеративные чтения становятся довольно медленными для большого количества кадров, которые я обрабатываю.

Есть ли более приятный способ сделать это? Я относительно новичок в PyTables, поэтому, если у вас есть какие-либо советы по организации наборов данных в больших массивах, я был бы рад их услышать.


person ali_m    schedule 16.06.2012    source источник
comment
Я думаю, что на самом деле это основное ограничение hdf5, а не ограничение pytables (здесь я могу ошибаться...). Во всяком случае, я считаю, что h5py гораздо более естественен для нетабличных данных. Однако в этом случае у него есть то же ограничение.   -  person Joe Kington    schedule 17.06.2012


Ответы (1)


Как бы то ни было, я часто делаю то же самое с трехмерными сейсмическими данными, хранящимися в формате hdf.

Итеративное чтение выполняется медленно из-за вложенных циклов. Если вы выполняете только один цикл (а не цикл по каждой строке), это довольно быстро (по крайней мере, при использовании h5py. Я обычно храню только табличные данные, используя pytables) и делает именно то, что вы хотите.

В большинстве случаев вам нужно перебирать списки индексов, а не каждую строку.

По сути, вы хотите:

roidata = np.vstack([bigarray[:,i,j] for i,j in zip(*roipixels)])

Вместо:

roidata = np.asarray([row[roipixels[0],roipixels[1]] for row in bigarray])

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

(Предостережение: я не проверял это с pytables, но с h5py все работает отлично.)

person Joe Kington    schedule 17.06.2012
comment
Спасибо, Джо. Я думаю, что это ответ на мой вопрос, но я был удивлен, обнаружив, что предложенная вами строка на самом деле читается намного медленнее в моем случае (примерно в 15 раз). Я не уверен, является ли это проблемой Pytables vs h5py, или это как-то связано с формой блока или сжатием, которые я использую. Я проверю h5py и посмотрю, работает ли он лучше. - person ali_m; 17.06.2012
comment
Вероятно, это контролируется размером фрагмента, с которым хранится ваш массив. Если базовый файл hdf оптимизирован для доступа по строкам, то доступ по строкам будет быстрее. Я не знаю, как pytables вычисляет размер фрагмента для использования. Удачи, во всяком случае! - person Joe Kington; 18.06.2012