2013-08-28 18 views
19

Ho un numero di file hdf5, ognuno dei quali ha un singolo set di dati. I set di dati sono troppo grandi per contenere la RAM. Vorrei combinare questi file in un singolo file contenente tutti i set di dati separatamente (ad esempio non per concatenare i set di dati in un singolo set di dati).Combinazione di file hdf5

Un modo per fare ciò è creare un file hdf5 e quindi copiare i dataset uno per uno. Questo sarà lento e complicato perché dovrà essere salvato nel buffer.

C'è un modo più semplice per farlo? Sembra che ci dovrebbe essere, dal momento che si tratta essenzialmente di creare un file contenitore.

Sto usando python/h5py.

+1

Sembra che questo abbia già risposto: http://stackoverflow.com/questions/5346589/concatenate-a-large-number-of-hdf5-files –

+2

@MattPavelle per quanto ho capito questo è diverso da quello che voglio . Non voglio concatenare i set di dati in un singolo set di dati, ma per mantenerli come set di dati separati all'interno di un unico file. – Bitwise

+1

Capito, grazie per il chiarimento e la modifica. E perdona il seguito - sono passati alcuni anni da quando ho giocato con HDF5 - ma presumo che h5merge non faccia il trucco? –

risposta

9

Una soluzione è quella di utilizzare l'interfaccia h5py al basso livello H5Ocopyfunction delle API HDF5, in particolare 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' 

Quanto sopra è stato generato con h5py versione 2.0.1-2+b1 e ipython versione 0.13.1-2+deb7u1 in cima alla versione Python 2.7.3-4+deb7u1 da un'installazione vanilla più o meno di Debian Wheezy. I file f1.h5 e f2.h5 non esistevano prima dell'esecuzione di quanto sopra.

Il hf1.flush() al comando [7] è fondamentale, come l'interfaccia di basso livello a quanto pare sarà sempre attingere alla versione del file .h5 memorizzato su disco, non che nella cache in memoria. Copiare i set di dati verso/da gruppi non presenti nella radice di un File può essere ottenuto fornendo l'ID di quel gruppo usando, ad es., hf1.get("g1").id.

Si noti che h5py.h5o.copy non riuscirà con un'eccezione (nessun clobber) se un oggetto del nome indicato esiste già nel percorso di destinazione.

+1

Questo sembra essere potenzialmente un paio d'anni troppo tardi, ma ... Lo userò sicuramente, e spero che se non altro aiuterà anche qualcun altro. – hBy2Py

+1

Grazie! In realtà questa domanda ottiene voti ogni tanto, quindi immagino che sia ancora utile per molte persone. – Bitwise

+0

Fresco. HDF5 è un formato di dati davvero bello, ma la sua API di alto livello è lontana da ... esauriente. – hBy2Py

9

Ho trovato una soluzione non python utilizzando h5copy dagli strumenti hdf5 ufficiali. h5copy può copiare singoli set di dati specificati da un file hdf5 in un altro file hdf5 esistente.

Se qualcuno trova una soluzione basata su python/h5py, sarei lieto di ascoltarla.

26

Questo è in realtà uno dei casi d'uso di HDF5. Se si desidera essere in grado di accedere a tutti i set di dati da un singolo file e non interessa come vengono effettivamente memorizzati su disco, è possibile utilizzare external links. Dalle HDF5 website:

Collegamenti esterni permettono un gruppo di includere gli oggetti in un altro file HDF5 e abilitare la libreria per accedere a tali oggetti come se fossero nel file corrente. In questo modo, è possibile che un gruppo contenga direttamente set di dati, tipi di dati denominati e persino gruppi che si trovano effettivamente in un file diverso. Questa funzionalità è implementata mediante una serie di funzioni che creano e gestiscono i collegamenti, definire e recuperare percorsi di oggetti esterni, e interpretare nomi dei collegamenti:

Here's how to do it in h5py:

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

Questo sarebbe molto più veloce di copiare tutti i set di dati in un nuovo file. Non so quanto sarebbe veloce l'accesso a otherfile.hdf5, ma il funzionamento su tutti i set di dati sarebbe trasparente - ovvero, h5py vedrebbe tutti i set di dati come residenti in foo.hdf5.

+0

Grazie, è un bel trucco. Nel mio caso, però, preferisco che siano contenuti in un unico file. Ma potrei usare questo metodo se la copia dimostra di essere troppo lenta. – Bitwise

+2

dovrebbe essere selezionato come risposta alla domanda. – ivotron

+0

Se hai intenzione di fare questo e hai molti link, assicurati di usare H5Pset_libver_bounds() in C o libver = 'latest' quando crei/apri nuovi file in h5py. Questo userà l'ultimo formato di file, che è molto più efficiente per la memorizzazione di un gran numero di link. –

1

Io di solito uso lo strumento ipython e h5copy insieme, questo è molto più veloce rispetto a una pura soluzione python. Una volta installato h5copy.

Soluzione console 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} 

console automatizzata soluzione

Per automatizzare completamente il processo di supponendo che si sta lavorando nella cartella sono stati i file da unire sono memorizzati:

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} 

Creare un nuovo gruppo per ogni .h5 file aggiunto

Se si desidera mantenere il set di dati precedente separato all'interno dell'output.h5, è necessario creare prima il gruppo utilizzando la bandiera -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

Per aggiornare su questo, con HDF5 versione 1.10 arriva una nuova funzionalità che potrebbe essere utile in questo contesto, chiamati "set di dati virtuali".
Qui trovate un breve tutorial e alcune spiegazioni: Virtual Datasets.
Qui ulteriori spiegazioni e documentazione complete e dettagliate per la funzione:
Virtual Datasets extra doc.
E qui la richiesta di pull unita in h5py per includere l'API dei datatset virtuali in h5py:
h5py Virtual Datasets PR ma non so se è già disponibile nella versione h5py corrente o verrà in seguito.

+0

Tuttavia, la creazione di un set di dati virtuale concatenerebbe (virtualmente) i set di dati, il che non è ciò che il poster originale voleva fare. –