2013-08-28 11 views
19

Ich habe eine Reihe von hdf5-Dateien, von denen jede einen einzigen Datensatz hat. Die Datensätze sind zu groß, um sie im RAM zu speichern. Ich möchte diese Dateien in einer einzigen Datei kombinieren, die alle Datensätze separat enthält (d. H. nicht, um die Datensätze zu einem einzigen Datensatz zu verketten).Kombination von hdf5-Dateien

Eine Möglichkeit besteht darin, eine hdf5-Datei zu erstellen und dann die Datensätze nacheinander zu kopieren. Dies wird langsam und kompliziert, da es eine gepufferte Kopie sein muss.

Gibt es eine einfachere Möglichkeit, dies zu tun? Scheint so, als sollte es sein, da es im Grunde nur eine Containerdatei erstellt.

Ich benutze Python/h5py.

+1

Sieht aus wie dies bereits beantwortet wurde: http://stackoverflow.com/questions/5346589/concatenate-a-large-number-of-hdf5-files –

+2

@MattPavelle soweit ich verstehe das ist anders als was ich will . Ich möchte die Datensätze nicht zu einem einzelnen Dataset verketten, sondern sie als separate Datasets in einer Datei speichern. – Bitwise

+1

Hab es, danke für die Klarstellung und die Bearbeitung. Und vergib das Follow-up - es ist ein paar Jahre her, seit ich mit HDF5 gespielt habe - aber ich nehme an, dass h5merge nicht den Trick macht? –

Antwort

9

Eine Lösung ist die h5py Schnittstelle zum Low-Level-H5Ocopyfunction der HDF5 API zu verwenden, insbesondere die 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' 

Die oben mit h5py Version 2.0.1-2+b1 und ipython Version erzeugt wurde 0.13.1-2+deb7u1 über Python Version 2.7.3-4+deb7u1 von einer mehr oder weniger Vanille-Installation von Debian Wheezy. Die Dateien f1.h5 und f2.h5 existierten nicht vor der Ausführung des oben genannten.

Die hf1.flush() in Befehl [7] ist von entscheidenden Bedeutung, da der Low-Level-Schnittstelle scheinbar immer von der Version der auf der Festplatte gespeichert .h5 Datei ziehen wird, nicht, dass im Arbeitsspeicher zwischengespeichert. Das Kopieren von Datensätzen zu/von Gruppen, die nicht an der Wurzel von File sind, kann durch Liefern der ID dieser Gruppe unter Verwendung von beispielsweise hf1.get("g1").id erreicht werden.

Beachten Sie, dass h5py.h5o.copy mit einer Ausnahme (kein Clobber) fehlschlägt, wenn ein Objekt mit dem angegebenen Namen bereits am Zielort existiert.

+1

Das sieht vielleicht ein paar Jahre zu spät aus, aber ... Ich werde es auf jeden Fall verwenden, und hoffentlich hilft es, wenn nichts anderes, auch jemand anderem. – hBy2Py

+1

Danke! Tatsächlich bekommt diese Frage hin und wieder Stimmen, also schätze ich, dass es für viele Leute immer noch nützlich ist. – Bitwise

+0

Kühl. HDF5 ist ein wirklich nettes Datenformat, aber seine High-Level-API ist bei weitem nicht ... erschöpfend. – hBy2Py

9

Ich fand eine nicht-Python-Lösung mit h5copy aus den offiziellen hdf5-Tools. h5copy kann einzelne angegebene Datensätze aus einer hdf5-Datei in eine andere vorhandene hdf5-Datei kopieren.

Wenn jemand eine python/h5py-basierte Lösung findet, würde ich mich freuen, davon zu hören.

26

Dies ist einer der Anwendungsfälle von HDF5. Wenn Sie nur aus einer einzigen Datei auf alle Datenmengen zugreifen möchten und sich nicht darum kümmern, wie sie tatsächlich auf der Festplatte gespeichert sind, können Sie external links verwenden. Aus den HDF5 website:

Externen Verbindungen ermöglichen eine Gruppe Objekte in einer anderen HDF5 Datei aufzunehmen und die Bibliothek zu ermöglichen, diese Objekte zugreifen, als ob sie in der aktuellen Datei sind. Auf diese Weise scheint eine Gruppe direkt Datensätze, benannte Datentypen und sogar Gruppen zu enthalten, die sich tatsächlich in einer anderen Datei befinden. Diese Funktion über eine Reihe von Funktionen implementiert, die die Links erstellen und verwalten, definieren und Wege zu externen Objekten abrufen und Linknamen interpretieren:

Here's how to do it in h5py:

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

Dies wäre sehr viel schneller als alle Datensätze in eine neue Datei zu kopieren. Ich weiß nicht, wie schnell der Zugriff auf otherfile.hdf5 wäre, aber die Arbeit an allen Datensätzen wäre transparent - das heißt, h5py würde alle Datensätze als in foo.hdf5 residieren sehen.

+0

Danke, das ist ein netter Trick. In meinem Fall bevorzuge ich jedoch, dass sie wirklich in einer Datei enthalten sind. Aber ich könnte diese Methode verwenden, wenn sich das Kopieren als zu langsam erweist. – Bitwise

+2

Dies sollte als Antwort auf die Frage ausgewählt werden. – ivotron

+0

Wenn Sie dies tun und viele Links haben, sollten Sie H5Pset_libver_bounds() in C oder libver = 'latest' verwenden, wenn Sie neue Dateien in h5py erstellen/öffnen. Dies wird das neueste Dateiformat verwenden, das zum Speichern einer großen Anzahl von Links viel effizienter ist. –

1

Normalerweise verwende ich ipython und h5copy Werkzeug togheter, das ist viel schneller im Vergleich zu einer reinen Python-Lösung. Einmal installiert h5copy.

Konsolenlösung 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} 

Automatisierte Konsole Lösung

den Prozess vollständig automatisieren Sie in dem Ordner, wurden die Dateien zusammengeführt werden arbeiten angenommen gespeichert sind:

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} 

eine neue Gruppe für jede .h5 erstellen Datei hinzugefügt

Wenn Sie den vorherigen Datensatz innerhalb der Ausgabe.h5 getrennt halten möchten, müssen Sie zuerst die Gruppe mit dem Flagerstellen:

# 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

auf diese zu aktualisieren, mit HDF5 Version 1.10 kommt eine neue Funktion, die in diesem Zusammenhang nützlich sein könnte „Virtual Dataset“ genannt.
Hier finden Sie ein kurzes Tutorial und einige Erläuterungen: Virtual Datasets.
Hier finden Sie weitere vollständige und detaillierte Erklärungen und Dokumentationen zum Merkmal:
Virtual Datasets extra doc.
Und hier die zusammengeführte Pull-Anfrage in h5py, um die virtuelle datsetsets API in h5py:
h5py Virtual Datasets PR aber ich weiß nicht, ob es bereits in der aktuellen h5py Version oder wird später kommen.

+0

Das Erstellen eines virtuellen Datasets würde die Datensätze (virtuell) verketten, was jedoch nicht das Ziel des ursprünglichen Posters war. –