(h5py dataset)/(numpy array) Zugriff mit : und ...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

Ich habe hier ein h5py dataset (das aehnelt numpy arrays), auf das ich per slicing zugreifen moechte.
Angenommen das Dataset ist von der Form 3x3x3x4 (die groesse kann auch voellig anders sein).

Mein eigentliches Ziel ist etwas in der Art "gib mir den ersten Wert in der vierten Dimension" und das wird umgewandelt in dset[:,:,:,1].

Wie realisiere ich sowas am besten (muss ich hier auf eval oder aehnliches zurueckgreifen oder gibt es dafuer einen pythonic Way?)?

EDIT: mit was aehnlichem meine ich natuerlich exec
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

Kaum debuggt man den Code schon erhält man eine recht vernünftige Lösung:

Code: Alles auswählen

dset.__getitem__((slice(None,None,None), slice(None,None,None), slice(None,None,None), 1))
BlackJack

@Liffi: Das ist auf keinen Fall vernünftig. Und wofür soll das eine Lösung sein? Warum schreibst Du das nicht normal als ``dset[:,:,:,1]``!? Was ist das Problem?
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

BlackJack hat geschrieben:@Liffi: Das ist auf keinen Fall vernünftig.
Damn, ich habs befuerchtet.
Und wofür soll das eine Lösung sein? Warum schreibst Du das nicht normal als ``dset[:,:,:,1]``!? Was ist das Problem?
Ok, ich werde mal versuchen es ein wenig zu beschreiben:

Ich bekomme von außen ein paar Daten geliefert.
Die Daten sehen dann irgendwie so aus: ('test', (1.0, 2, 30)).
Die Werte müssen nicht unbedingt floats oder ints sein, sondern koennen auch aus Strings bestehen. Ich mappe das ganze dann auf integer Werte.
Aus denen bastele ich dann einen Hypercube mit h5py.

Angenommen der Wuerfel waere vierdimensional (5x4x3x4) und 'test' waere hierbei die dritte Dimension dann soll ein getData('test', 30') dset[:,:,2,:] liefern.

Ich hoffe, ich hab das jetzt einigermassen vernuenftig dargestellt.
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

Ich hab meinen Code mal aufs noetigste reduziert (hoffe ich).
BlackJack

@Liffi: Warum stecken die Funktionen alle in einer Klasse? `self` wird nicht wirklich benutzt, es gibt keine `__init__()`, damit würde ich das als Missbrauch einer Klasse werten. Zu welchem Zweck?

Die Docstrings stehen an der falschen Stelle. Die müssen nach den ``def``-Anweisungen stehen und nicht davor.

Diese Datenstruktur in `create()` und die ganze Indexerei finde ich insgesamt recht undurchsichtig und verwirrend. Ich würde `args` da nicht verändern, sondern `arglist` aus neuen Objekten aufbauen. Solche Nebeneffekte sind unschön und können zu schwer lokalisierbaren Fehlern führen. `dimensions` wird nicht verwendet, kann also weg. Die Klammern um `dims` in Zeile 25 sind überflüssig. Die Liste hätte man auch mit einer "list comprehension" kompakter erstellen können. `pickle`-Dateien sollte man *immer* im Binärmodus öffnen. Sonst sind sie nicht zwischen Plattformen austauschbar.

`read()` ist sehr langatmig hingeschrieben. Das geht deutlich kompakter:

Code: Alles auswählen

def read(filename='hdf_mapping'):
    with open(filename, 'rb') as mapping_file:
        return dict(pickle.load(mapping_file))
Wobei man sich natürlich die Fragen stellen kann warum das nicht gleich als Dictionary gespeichert wurde. Das lässt sich in der `create()`-Funktion mit einer einzigen Zeile erstellen:

Code: Alles auswählen

    mapping = dict((k , [i, v]) for i, (k, v) in enumerate(args))
In `getdata()` lässt sich die Initialisierung von `indices` etwas kompakter schreiben: ``indices = [slice(None, None, None)] * len(dset.shape)`` statt der Schleife.

Warum verwendest Du `dset.__getitem__()` statt `dset[]`!?

Und was ist jetzt nochmal die Frage!?
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

BlackJack hat geschrieben:@Liffi: Warum stecken die Funktionen alle in einer Klasse? `self` wird nicht wirklich benutzt, es gibt keine `__init__()`, damit würde ich das als Missbrauch einer Klasse werten. Zu welchem Zweck?
Hinterher soll das ganze als Modul innerhalb eines Programms arbeiten. Die ganzen hartkodierten Strings sollten dann in die (dann vorhandene) __init__.
Oder ist das Vorgehen dann nicht sinnvoll?
Die Docstrings stehen an der falschen Stelle. Die müssen nach den ``def``-Anweisungen stehen und nicht davor.
Ups.
`pickle`-Dateien sollte man *immer* im Binärmodus öffnen. Sonst sind sie nicht zwischen Plattformen austauschbar.
Gut zu wissen, danke.
`read()` ist sehr langatmig hingeschrieben. Das geht deutlich kompakter:
Und wirkt auch noch klarer :-).
Wobei man sich natürlich die Fragen stellen kann warum das nicht gleich als Dictionary gespeichert wurde. Das lässt sich in der `create()`-Funktion mit einer einzigen Zeile erstellen
Ich sehe ich kann hier noch eine Menge lernen.
Warum verwendest Du `dset.__getitem__()` statt `dset[]`!?
Weil ich es verrafft habe.

Der Code ist jetzt wesentlich sauberer und ich hoffe, dass ich die Vielzahl an Dingen die ich hier gelernt habe in Zukunft umsetzen kann.
Ganz herzlichen Dank!
BlackJack

@Liffi: Nur die Zeichenketten als gemeinsame Daten halte ich nicht für eine sinnvolle Klasse. `h5creator` mit einer Methode `create()` erinnert mich stark an Execution in the Kingdom of Nouns. Wir sind hier aber nicht bei Java sondern bei Python. :-) Ich kenne das Problem ja nicht was Du lösen möchtest, aber wenn ich mir den Quelltext so anschaue würde es vielleicht Sinn machen das `mapping` und `dset` in einem Objekt zu Kapseln. Die gehören ja anscheinend zusammen.

Insgesamt denke ich Deine Herangehensweise an die Entwicklung ist nicht so gut. Erst eine Klasse erstellen mit einem Haufen Funktionen und dann später mal schauen wie man da vielleicht eine *echte* Klasse daraus machen kann, birgt eine grosse Gefahr, dass am Ende so etwas einfach im Programm stehen bleibt. Besser mit Funktionen anfangen und erst wenn man sieht, dass man die sinnvoll zu einer Klasse zusammenfassen kann, das auch wirklich tun. So hat man immer einen saubere(re)n Entwurf. Gute Vorsätze wie "den Code muss ich irgendwann mal aufräumen" bleiben nämlich oft genug aus Zeitmangel auf der Strecke.

Warum wird die `pickle()`-Datei bei `create()` eigentlich nicht geschlossen? Wird da noch etwas reingeschrieben? Und handelt es sich bei den `h5py.File`-Objekten um das HDF5-Datenformat? Da müsste man das `mapping` doch eigentlich als Zeichenkette picklen können und als Metadaten mit in die HDF5-Datei stecken können, statt sie extra zu speichern!?
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

BlackJack hat geschrieben:Wir sind hier aber nicht bei Java sondern bei Python. :-)

Sehr schoener Text, vielleicht trage ich wirklich noch zu viel Javadenken im Kopf mit mir rum.
Und handelt es sich bei den `h5py.File`-Objekten um das HDF5-Datenformat? Da müsste man das `mapping` doch eigentlich als Zeichenkette picklen können und als Metadaten mit in die HDF5-Datei stecken können, statt sie extra zu speichern!?
Ja, es handelt sich um HDF5 .
Und ab jetzt ist das mapping als Attribut in der HDF5 Datei.

Danke.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

PyTables baut auf HDF5 auf, ist schnell, verläßlich und funktioniert zusammen mit numpy. Was will man mehr? ;-)

Gruß,
Christian
Liffi
User
Beiträge: 153
Registriert: Montag 1. Januar 2007, 17:23

CM hat geschrieben:PyTables baut auf HDF5 auf, ist schnell, verläßlich und funktioniert zusammen mit numpy. Was will man mehr? ;-)
h5py ist imho noch eine Spur näher dran an numpy.
Antworten