netcdf - Teilarrays lesen

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
derbernd
User
Beiträge: 13
Registriert: Montag 6. Oktober 2014, 08:19

Hallo,

ich teste gerade python als Alternative zu Matlab. In Matlab kann man recht unkompliziert mit netCDF-Files umgehen und die meisten Befehle konne ich auf python übertragen.

Da ich relative große Datenmengen verarbeiten möchte und nur Teilbereiche der Datenmenge benötige, lese ich mir in Matlab nur eine Auswahl ein.

Code: Alles auswählen

data = netcdf.getVar(ncid, varid, [0 0 timeStart], [sizex sizey  timeDiff+1]);
Mittels python würde ich die Daten so:

Code: Alles auswählen

f.variables['lat'][:]
auslesen, wobei innerhalb der letzten Klammer ein Bereich stehen würde.

Wie kann ich dynamisch einen Vektor (Matlab) angeben, der mir ermöglicht nur einen Teilbereich auszulesen.

Danke

Nachtrag: Analog zu dem Beispiel auf Folie 13 und 14 http://snowball.millersville.edu/~adeca ... -files.pdf
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

derbernd hat geschrieben:Mittels python würde ich die Daten so:

Code: Alles auswählen

f.variables['lat'][:]
auslesen, wobei innerhalb der letzten Klammer ein Bereich stehen würde.
Ist das nicht bereits die Antwort auf deine Frage? Genau so greift man in Python auf Teilbereiche von sequenzartigen Typen zu. Nur wenn ein Typ diese Art des Zugriffs nicht unterstützt, dann muss man andere Wege finden. Ist deine Frage vielleicht so gemeint, dass du mit einem Objekt arbeiten musst, dass die besagte Unterstützung nicht eingebaut hat?
derbernd
User
Beiträge: 13
Registriert: Montag 6. Oktober 2014, 08:19

unsicher... Gibt es eine Möglichkeit die [:] mit einen Vektor dynamisch zu ersetzen?

aus [:] sollte [timeDiff, height, lat, lon] werden
BlackJack

@snafu: Die Frage ist so gemeint das der OP gerne so ein Slice aus der Datei haben möchte ohne vorher das gesamte Array aus der Datei in den Speicher zu lesen. Hinter ``f.variables['lat']`` steckt nämlich ein Ladevorgang aus der netCDF-Datei.

@derbernd: Die Frage im letzten Beitrag habe ich nicht verstanden!?
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Mit netCDF habe ich bisher noch nicht gearbeitet, aber mit hdf5.
"netCDF version 4 has many features not found in earlier versions of the library and is implemented on top of HDF5" (https://pypi.python.org/pypi/netCDF4/0.8.2)
Beim Zugriff auf hdf5 kanst Du mit der Slicing-Syntax Teil-Arrays auslesen:

Code: Alles auswählen

f.variables['lat'][2000:4000]
Es werden 2000 Elemente aus dem Array 'lat' gelesen von Element 2000 (einschließlich) bis Element 4000 (ausschließlich).
derbernd hat geschrieben:aus [:] sollte [timeDiff, height, lat, lon] werden

Code: Alles auswählen

lat = f.variables['lat'][:]
lat.shape = (timeDiff, height, lat, lon)
Das geht aber nur wenn gilt

Code: Alles auswählen

lat.size == timeDiff * height * lat * lon
a fool with a tool is still a fool, www.magben.de, YouTube
derbernd
User
Beiträge: 13
Registriert: Montag 6. Oktober 2014, 08:19

@MagBen: Danke für den Ansatz. Es gibt ein Verständnisproblem bei deinem Code. Mittels

Code: Alles auswählen

lat = f.variables['lat'][:]
lese ich doch die gesamten Daten aus und mittels *.shape verändert man doch die Größe des Feldes. Somit habe ich vielleicht einen Teil, jedoch muss ich erstmal die gesamte Datenmenge einlesen.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

derbernd hat geschrieben:lese ich doch die gesamten Daten aus und mittels *.shape verändert man doch die Größe des Feldes. Somit habe ich vielleicht einen Teil, jedoch muss ich erstmal die gesamte Datenmenge einlesen.
Das hängt davon ab, wie es implementiert ist.

Code: Alles auswählen

lat_node = f.variables['lat']
lat_node wäre in hdf5 kein Numpy-Array mit den Daten, sondern ein Node-Objekt zum Zugriff auf die Daten.

Code: Alles auswählen

lat_part = lat_node[2000:4000]
jetzt würde in hdf5 ein Teil des Arrays gelesen werden und Dir als Numpy-Array zurückgegeben werden.

Code: Alles auswählen

lat_part.shape = (4,5,50,2) 
Wenn 'lat' ein 1D-Array in der Datei ist, dann ist auch lat_part ein 1D-Array, das Du aber auf beliebige Dimensionen ändern kannst, ohne dass Speicher neu angelegt oder Daten kopiert werden. Die Anzahl der Elemente darf sich dabei aber nicht ändern.
a fool with a tool is still a fool, www.magben.de, YouTube
BlackJack

@MagBen: Das mit dem Shape habe ich nicht verstanden!? ``f.variables['lat'][2000:4000]`` liefert doch schon ein Array mit der richtigen Form, also *kein* 1D-Array (es sei denn man hat tatsächlich nur eine Dimension in der Variable gespeichert).

@derbernd: Diesen Teil habe ich nicht verstanden: „aus [:] sollte [timeDiff, height, lat, lon] werden”. Auf jeden Fall scheint „slicing” die Antwort auf Dein Problem zu sein. Du musst halt nur noch heraus finden wie Du das Argument für den Indexzugriff gestalten musst, damit Du das gewünschte Ergebnis bekommst.
derbernd
User
Beiträge: 13
Registriert: Montag 6. Oktober 2014, 08:19

Ich teste dies heute Nachmittag und werde gegebenenfalls eine Lösung bzw. weitere Fragen posten
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

BlackJack hat geschrieben:``f.variables['lat'][2000:4000]`` liefert doch schon ein Array mit der richtigen Form, also *kein* 1D-Array (es sei denn man hat tatsächlich nur eine Dimension in der Variable gespeichert).
Kann sein, kann auch nicht sein. Dazu müsste ich wissen welche Dimension das Array lat in der Datei hat. Wenn es 1D ist, dann kann man die Dimension durch eine Zuweisung zu shape nachträglich verändern. Ist es dagegen schon so 4D wie es gebraucht wird, dann kann man shape auch verändern, braucht es aber vielleicht gar nicht.
a fool with a tool is still a fool, www.magben.de, YouTube
BlackJack

@MagBen: Wenn die Daten nicht als mehrdimensionales Array gespeichert sind, dann müsste man beim Slicen ja auch aufpassen das man einen richtigen Anfang und eine korrekte Länge berechnet. Das wäre nervig, fehleranfällig, und das Dateiformat und die Bibliothek nehmen einem das auch alles ab. Das wäre echt sehr unsinnig ein eigendlich mehrdimensionales Array ”flat” in eine netCDF-Datei zu speichern. Und im Beispiel des Matlab-Codes der ersetzt werden soll haben wir ja auch ein dreidimensionales Array, jedenfalls werden da für drei Dimensionen die Start-/Endwerte angegeben.

@derbernd: Nachdem ich jetzt mal in der Matlab-Doku gelesen und im Netz nach Beispielen gesucht habe, würde ich mal ganz frech folgendes behaupten:

Code: Alles auswählen

data = netcdf.getVar(ncid, varid, [0 0 timeStart], [sizex sizey  timeDiff+1]);
würde in Python so aussehen:

Code: Alles auswählen

data = dataset.variables[variable_name][:sizex, :sizey, time_start:time_diff + 1]
Falls ``sizex`` und/oder ``sizey`` immer der länge der jeweiligen Dimension entsprechen sollte, braucht man die Werte an der Stelle nicht angeben und kann einfach nur den Doppelpunkt verwenden.
derbernd
User
Beiträge: 13
Registriert: Montag 6. Oktober 2014, 08:19

ich habe es jetzt testen können und es läuft! Vielen Dank für die Hilfe.

Eine Frage ist mir dann doch noch eingefallen. Die Reihenfolge der Parameter in der letzten Klammer ist variabel. Die Position (Anordnung) kann aber über den Name der Dimension bestimmt werden. Wie könnte ich dies in python berücksichtigen? Mir würde momentan nur ein if-else-Konstrukt einfallen.

Nachfolgend ein Beispiel

Code: Alles auswählen

data.variables[var_name][time,height,lat,lon]
data.variables[var_name][time,lat,lon,height]
BlackJack

@derbernd: Das könnte man mit einem ``if``/``else`` lösen wenn es zwei Möglichkeiten gibt. Falls die Namen immer gleich sind und nur die Reihenfolge variiert könnte man es auch generischer lösen.
Antworten