Объединение файлов hdf5
У меня есть несколько файлов hdf5, каждый из которых имеет один набор данных. Наборы данных слишком велики для хранения в ОЗУ. Я хотел бы объединить эти файлы в один файл, содержащий все наборы данных отдельно (т.е. не, чтобы объединить наборы данных в один набор данных).
Один из способов сделать это - создать файл hdf5, а затем скопировать данные по одному. Это будет медленным и сложным, потому что нужно будет буферизовать копию.
Есть ли более простой способ сделать это? Похоже, что должно быть, так как это просто создание файла контейнера.
Я использую python/h5py.
Ответы
Ответ 1
Одним из решений является использование интерфейса h5py
для низкоуровневой H5Ocopy
функция:
In [1]: import h5py as h5
In [2]: hf1 = h5.File("f1.h5")
In [3]: hf2 = h5.File("f2.h5")
In [4]: hf1.create_dataset("val", data=35)
Out[4]: <HDF5 dataset "val": shape (), type "<i8">
In [5]: hf1.create_group("g1")
Out[5]: <HDF5 group "/g1" (0 members)>
In [6]: hf1.get("g1").create_dataset("val2", data="Thing")
Out[6]: <HDF5 dataset "val2": shape (), type "|O8">
In [7]: hf1.flush()
In [8]: h5.h5o.copy(hf1.id, "g1", hf2.id, "newg1")
In [9]: h5.h5o.copy(hf1.id, "val", hf2.id, "newval")
In [10]: hf2.values()
Out[10]: [<HDF5 group "/newg1" (1 members)>, <HDF5 dataset "newval": shape (), type "<i8">]
In [11]: hf2.get("newval").value
Out[11]: 35
In [12]: hf2.get("newg1").values()
Out[12]: [<HDF5 dataset "val2": shape (), type "|O8">]
In [13]: hf2.get("newg1").get("val2").value
Out[13]: 'Thing'
Выше была создана версия h5py
version 2.0.1-2+b1
и версия iPython 0.13.1-2+deb7u1
поверх версии Python 2.7.3-4+deb7u1
из более или менее ванильной установки Debian Wheezy. Файлы f1.h5
и f2.h5
не существовали до выполнения вышеуказанного.
Команда hf1.flush()
в команде [7]
имеет решающее значение, так как интерфейс низкого уровня, по-видимому, всегда будет извлекаться из версии файла .h5
, хранящегося на диске, а не в кэше в памяти. Копирование наборов данных в/из групп не в корневом каталоге File
может быть достигнуто путем подачи идентификатора этой группы с использованием, например, hf1.get("g1").id
.
Обратите внимание, что h5py.h5o.copy
завершится с исключением (без clobber), если объект указанного имени уже существует в месте назначения.
Ответ 2
Это фактически один из вариантов использования HDF5.
Если вы просто хотите иметь доступ ко всем наборам данных из одного файла, и им все равно, как они фактически хранятся на диске, вы можете использовать external ссылки. На веб-сайте HDF5:
Внешние ссылки позволяют группе включать объекты в другой файл HDF5 и позволяют библиотеке обращаться к этим объектам так, как если бы они находились в текущем файле. Таким образом, группа может, как представляется, напрямую содержать наборы данных, имена типов данных и даже группы, которые фактически находятся в другом файле. Эта функция реализована с помощью набора функций, которые создают и управляют ссылками, определяют и извлекают пути к внешним объектам и интерпретируют имена ссылок:
Здесь, как это сделать в h5py:
myfile = h5py.File('foo.hdf5','w')
myfile['ext link'] = h5py.ExternalLink("otherfile.hdf5", "/path/to/resource")
Это будет намного быстрее, чем копирование всех наборов данных в новый файл. Я не знаю, насколько бы быстрым был доступ к otherfile.hdf5
, но работа на всех наборах данных была бы прозрачной - то есть h5py увидит все наборы данных как находящиеся в foo.hdf5
.
Ответ 3
Я нашел решение, отличное от python, используя h5copy из официальных инструментов hdf5. h5copy может копировать отдельные указанные наборы данных из файла hdf5 в другой существующий файл hdf5.
Если кто-то найдет решение на основе python/h5py, я был бы рад услышать об этом.
Ответ 4
Я обычно использую ipython и h5copy tool togheter, это намного быстрее по сравнению с чистым решением python. После установки h5copy.
Консольное решение M.W.E.
#PLESE NOTE THIS IS IPYTHON CONSOLE CODE NOT PURE PYTHON
import h5py
#for every dataset Dn.h5 you want to merge to Output.h5
f = h5py.File('D1.h5','r+') #file to be merged
h5_keys = f.keys() #get the keys (You can remove the keys you don't use)
f.close() #close the file
for i in h5_keys:
!h5copy -i 'D1.h5' -o 'Output.h5' -s {i} -d {i}
Автоматическое консольное решение
Чтобы полностью автоматизировать процесс, предполагающий, что вы работаете в папке, хранятся файлы, которые нужно объединить:
import os
d_names = os.listdir(os.getcwd())
d_struct = {} #Here we will store the database structure
for i in d_names:
f = h5py.File(i,'r+')
d_struct[i] = f.keys()
f.close()
# A) empty all the groups in the new .h5 file
for i in d_names:
for j in d_struct[i]:
!h5copy -i '{i}' -o 'output.h5' -s {j} -d {j}
Создайте новую группу для каждого добавленного файла .h5
Если вы хотите сохранить предыдущий набор данных отдельно в output.h5, вам сначала нужно создать группу, используя флаг -p
:
# B) Create a new group in the output.h5 file for every input.h5 file
for i in d_names:
dataset = d_struct[i][0]
newgroup = '%s/%s' %(i[:-3],dataset)
!h5copy -i '{i}' -o 'output.h5' -s {dataset} -d {newgroup} -p
for j in d_struct[i][1:]:
newgroup = '%s/%s' %(i[:-3],j)
!h5copy -i '{i}' -o 'output.h5' -s {j} -d {newgroup}
Ответ 5
Чтобы обновить эту версию, в HDF5 версии 1.10 появилась новая функция, которая может быть полезна в этом контексте под названием "Виртуальные наборы данных".
Здесь вы найдете краткое руководство и некоторые пояснения:
Виртуальные наборы данных.
Здесь более полные и подробные объяснения и документация по этой функции:
Дополнительные данные Datasets.
И здесь объединенный запрос pull в h5py для включения API виртуальных datatsets в h5py:
h5py Virtual Datasets PR, но я не знаю, уже ли он доступен в текущей версии h5py или будет позже.