2013-08-28 3 views
19

У меня есть несколько файлов hdf5, каждый из которых имеет один набор данных. Наборы данных слишком велики для хранения в ОЗУ. Я хотел бы объединить эти файлы в один файл, содержащий все наборы данных отдельно (т. Е. не, чтобы объединить наборы данных в один набор данных).Сочетание файлов hdf5

Один из способов сделать это - создать файл hdf5, а затем скопировать данные по одному. Это будет медленным и сложным, потому что нужно будет буферизовать копию.

Есть ли более простой способ сделать это? Похоже, должно быть, так как это просто создание файла контейнера.

Я использую python/h5py.

+1

Похоже, на это был дан ответ уже: http://stackoverflow.com/questions/5346589/concatenate-a-large-number-of-hdf5-files –

+2

@MattPavelle, насколько я понимаю, это отличается от того, что я хочу , Я не хочу объединять данные в единый набор данных, но хранить их в виде отдельных наборов данных в одном файле. – Bitwise

+1

Получил это, спасибо за разъяснение и редактирование. И простить продолжение - прошло несколько лет с тех пор, как я играл с HDF5 - но я полагаю, что h5merge не делает трюк? –

ответ

9

Одно из решений состоит в использовании интерфейс h5py с низким уровнем H5Ocopyfunction из API HDF5, в частности h5py.h5o.copyfunction:

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 версии 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), если объект указанного имени уже существует в целевом местоположении.

+1

Это выглядит потенциально на пару лет слишком поздно, но ... Я определенно буду использовать его, и, надеюсь, если ничего другого он не поможет кому-то еще. – hBy2Py

+1

Спасибо! На самом деле этот вопрос получает голоса время от времени, поэтому я предполагаю, что он по-прежнему полезен для многих людей. – Bitwise

+0

Прохладный. HDF5 - действительно хороший формат данных, но его высокоуровневый API далеко не ... исчерпывающий. – hBy2Py

9

Я нашел решение, отличное от python, с помощью h5copy из официальных инструментов hdf5. h5copy может копировать отдельные указанные наборы данных из файла hdf5 в другой существующий файл hdf5.

Если кто-то найдет решение на основе python/h5py, я был бы рад услышать об этом.

26

Это на самом деле один из вариантов использования HDF5. Если вы просто хотите иметь доступ ко всем наборам данных из одного файла, и все равно, как они хранятся на диске, вы можете использовать external links. Из HDF5 website:

Внешних ссылок позволяют группе включать объекты в другом файл HDF5 и включить библиотеку для доступа к этим объектам, как будто они находятся в текущем файле. Таким образом, группа может, как представляется, напрямую содержать наборы данных, имена типов данных и даже группы, которые фактически находятся в другом файле. Эта функция реализуется с помощью набора функций, которые создают и управляют ссылками, определение и извлечение путей к внешним объектам, и интерпретировать имена ссылок:

Here's how to do it in h5py:

myfile = h5py.File('foo.hdf5','w') 
myfile['ext link'] = h5py.ExternalLink("otherfile.hdf5", "/path/to/resource") 

Это было бы гораздо быстрее чем копирование всех наборов данных в новый файл. Я не знаю, как бы быстрый доступ к otherfile.hdf5 был бы, но работа на всех наборах данных была бы прозрачной - то есть h5py увидит все наборы данных как находящиеся в foo.hdf5.

+0

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

+2

это должно быть выбрано как ответ на вопрос. – ivotron

+0

Если вы собираетесь сделать это, и у вас много ссылок, обязательно используйте H5Pset_libver_bounds() в C или libver = 'latest' при создании/открытии новых файлов в h5py. Это будет использовать последний формат файла, который намного эффективнее для хранения большого количества ссылок. –

1

Я обычно использую ipython и h5copy инструмент 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} 
1

Чтобы обновить на это, с HDF5 версии 1.10 приходит новая функция, которая может оказаться полезной в этом контексте под названием «Virtual Datasets».
Здесь вы найдете краткое руководство и некоторые пояснения: Virtual Datasets.
Здесь более полные и подробные пояснения и документацию по данной функции:
Virtual Datasets extra doc.
И здесь объединенный запрос на pull в h5py для включения API виртуальных datatsets в h5py:
h5py Virtual Datasets PR, но я не знаю, уже ли он доступен в текущей версии h5py или придет позже.

+0

Создание виртуального набора данных (фактически) объединит набор данных, хотя это не то, что хотел сделать оригинальный плакат. –

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