Verfasst am: 15.10.2014, 13:44
Titel: Out of memory bei csv-Import
Hallo zusammen.
Ich bin relativ neu hier und habe ein Problem, dass ich durch googlen bisher nicht lösen konnte.
Ich habe eine Funktion geschrieben, die mir den Inhalt von csv-Dateien in ein Cell-Array einliest, wenn ich sie anwende gibt Matlab mir aber einen 'out of memory' Fehler aus.
Die 'Inputdateien' haben 13 Spalten mit entweder Zahlen oder Strings als Inhalt und unterschiedliche Anzahlen von Zeilen (~800 000).
Ist das einfach schlecht implementiert, oder ist mein Rechner zu schwach auf der Brust?
Es ist ein 32Bit Matlab auf eine 32Bit Windwos7 Professional. Die ausgabe von MEMORY ist:
Code:
Maximum possible array: 864 MB
Memory available forall arrays: 1313MB
Memory used by MATLAB: 457 MB
Physical Memory(RAM): 3481MB
Durch etwas ausprobieren habe ich herausgefunden, dass MATLAB die Datei einlesen kann wenn ich die Zeilenzahl n auf n=669273 setze. Für n>669273 gibt es die 'Out of memory' Fehlermeldung.
Ich hoffe jemand findet die Zeit und kann mir weiterhelfen
Da brauchst Du entweder mehr RAM (ab spätestens 4GB (eher ab 3) brauchst Du dann sinnvollerweise ein 64-Bit Betriebssystem) oder Du musst vielleicht mal darüber nachdenken, ob Du wirklich alle Daten gleichzeitig im Arbeitsspeicher haben musst.
hmm. 800 000 x 13 ist schon zuviel? und ich kann da durch programmieren nichts ausbessern sondern muss aufrüsten und/oder das System runterschmeißen?
Da würde ich es eher stückweise einlesen.
Gibt es eine Fausregel wieviel (Zeilen) mein System dann schafft? Wenn ich den Output (C) dann noch einige Male weiter verwenden möchte?
Ein entscheidender Punkt ist auch, welche Art Daten. Länglicher Text braucht mehr Speicher als numerische Daten.
Brauchst du wirklich alle Textspalten? Wenn nicht, solltest du die nicht benötigten überspringen ( %*s statt %s ).
Unabhängig davon sind Dataset Arrays (vor R2013b) oder Tables (ab R2013b) besser geeignet, heterogene Daten zu speichern, als das bei Cell Arrays der Fall ist.
Ein String braucht je Zeichen 1 Byte Platz, ein double 8 Byte, ein single 4 Byte. Eine m x n Matrix, die Double-Werte enthält braucht also m*n*8 Byte.
Ganz vereinfacht angenommen, dass Du nur double-Werte einliest, macht das bei Dir also 800000*13*8Byte = 83,2MB. Das sollte kein Problem sein. Wenn Du viele lange Strings einliest, kann es aber schnell eng werden. Dann entspricht der Platz, den Du brauchst etwa der Dateigröße von der Datei, die Du einliest.
Allerdings verschwendest Du in Deinem Programm auch recht viel Speicher, weil Du die Werte aus Data ja nochmal in andere Variablen schreibst und die dann zum Teil wieder in ein cell konvertierst, die Du dann wieder in eine neue Matrix C kopierst. Dann hast Du die Daten ja nicht nur ein mal im Speicher liegen sondern so ungefähr 3 oder 4 mal also Kopie.
Interessanterweise wird so aber die Zahl der Zeilen die die Funktion schafft weniger. (Vorher: 669273; Jetzt schafft es nicht einmal 660000)
Ansonsten ist der Code so natürlich viel schöner und übersichtlicher.
@Epfi und @Harald:
Es sind schon einige längere strings dabei.
Es gibt auch eine Spalte deren Einträge entwerde Integer, 'null', oder leer (kein Eintrag) sind. Kann man das effizienter abfragen? In 3 Spalten ist mir aufgefallen, dass es viele Nachkommerstellen gibt und %d nicht genau genug ist.
Ich kann mir aber auch manche Werte als (positive) Integer übergeben lassen und die letzte Spalte weglassen (war leer) und komme dann auf:
Code:
Data = textscan(fid, '%s %u %s %f %f %u %s %f %s %s %s %s', n, 'headerlines', 1, 'delimiter', ';');
...
Data = [Data{1,}, num2cell({Data{2}), Data{3}, num2cell(Data{[4,5,6]}, Data{7}, num2cell(Data{8}, Data{[9,10,11,12]}];
Das ist aber auch nicht wesentlich besser. Ich vermute, weil num2cell entprechend öfters aufgerufen wird. (?)
@Harald
Ich verwende MATLAB R2014a, das gesamte Projekt, sollte aber später auch auf einem Rechner mit R2012 laufen, deswegen würde ich die dataset Variante vorziehen. Was datasets (und readtables) angeht, habe ich überhaut keine Erfahrung, aber mein erster Versuch:
Code:
Data = dataset('file', 'meineDatei.csv', 'delimiter', ';')
Hier gibt es den Hinweis:
Warning: Variable names were modified to make them valid MATLAB identifiers.
Und wenn ich die große Datei einlesen möchte eine seltsame Fehlermeldung:
Caugth "std::exception" Exception message is:
Message Catalog MATLAB:legacy_two_part was not loaded from the file. Please check file location, format and contents
Also stellt sich mir die Frage, komm ich mit datasets weiter, und kann ich da später auch allgemeine Operationen ausführen (zB. der Befehl sortrows funktioniert ja auch für datasets)?
Oder liegt bei mir allgemein was im Argen? 'Not loaded from file' hört sich ja nicht so gut an, ich weiß aber nicht genau, was es bedeuten soll.
Es gibt auch eine Spalte deren Einträge entwerde Integer, 'null', oder leer (kein Eintrag) sind. Kann man das effizienter abfragen?
Da bietet sich ein nominal / categorical array an. Ist der Integer wirklich als Zahl oder als String enthalten? Wenn 'null' dabei ist, deutet das ja auf einen String hin.
Generell ist da auch die Formatoption %C interessant.
Zitat:
In 3 Spalten ist mir aufgefallen, dass es viele Nachkommerstellen gibt und %d nicht genau genug ist.
%d ist integer, also gar keine Nachkommastellen. Da wäre die Alternative %f32.
Für kleinere, ganzzahlige Werte kann auch int8 oder int16 ausreichen, ggf. vorzeichenlos.
Zitat:
deswegen würde ich die dataset Variante vorziehen.
Einerseits verständlich. Andererseits ist es denkbar, dass bei den Tables als Nachfolger von Datasets intern einiges optimiert wurde.
Bei Datasets steht übrigens:
Zitat:
The dataset data type might be removed in a future release. To work with heterogeneous data, use the MATLAB® table data type instead. See MATLAB table documentation for more information.
Ist also die Frage, ob einem die Vergangenheit oder die Zukunft wichtiger ist ;)
Davon abgesehen gibt es auch Konvertierungsfunktionen wie dataset2table.
Beim Aufruf von dataset mit gemischten Daten würde ich, ähnlich wie bei textscan, ein 'Format' übergeben.
Zitat:
Hier gibt es den Hinweis:
Warning: Variable names were modified to make them valid MATLAB identifiers.
Das kann man erst mal ignorieren. Wenn du die Variable im Workspace anschaust, siehst du eben, dass die Spaltenüberschriften angepasst wurden.
Grundsätzlich wäre es hilfreich, wenn du einen (relativ kleinen) Beispieldatensatz zur Verfügung stellen kannst.
%d ist integer, also gar keine Nachkommastellen. Da wäre die Alternative %f32.
Für kleinere, ganzzahlige Werte kann auch int8 oder int16 ausreichen, ggf. vorzeichenlos.
Ich hatte jetzt %f und %u verwendet (es sind Zahlen mit 15 Nachkommastellen und positive ganze Zahlen mit maximal 4 Stellen)
Was ist denn der genaue Unterschied zwischen %f und %f32?
Zitat:
Davon abgesehen gibt es auch Konvertierungsfunktionen wie dataset2table.
Das war mir tatsächlich nicht bewusst. Aber das Problem ist nach wie vor, dass ich zum Programmieren die neuere Version 2014a und zum Ausführen die ältere 2012 verwenden muss.
noch mit dem Entsprechenden dataset Befehl, die gesamte Datei einlesen kann.
Ich könnte mit etwas aufwand das System auf Win7 64Bit upgraden und auch 64Bit MATLAB installieren oder einen neuen (maximal 8gb) Arbeitsspeicher einbauen.
Verspricht sich das Problem dadurch zu lösen?
Ansonsten gäbe es noch die Möglichkeit den Datensatz stückweise einzulesen..
PS. einen kleinen Beispieldatensatz habe ich angehängt:
Wie gesagt in X und Y sind Zahlen mit 15 Nachkommastellen, die ich auch gerne möglichst genau hätte. In 'Zeit' steht momentan noch eine Datumsangabe, deswegen lese ich als string ein. Später bekomme ich allerdings einen Sekundenwert.
Danke für die Hilfe bisher, auch wenn es mich nicht (direkt) weitergebracht hat, konnte ich doch mein MATLAB-Wissen erweitern
Kann klappen, muss aber nicht. Ein Hard- und/oder Softwareupgrade wäre für mich immer die letzte Alternative. Die meisten Probleme lassen sich mit ein bisschen Nachdenken auch auf der alten Hardware lösen.
gomar hat Folgendes geschrieben:
Ansonsten gäbe es noch die Möglichkeit den Datensatz stückweise einzulesen..
Ist nicht immer möglich, aber wenn Du einfach nur einen Datensatz nach dem anderen Bearbeiten kannst, wäre das sicherlich die cleverste Variante.
Wenn ich den Datensatz so sehe, könnte es auch sein, dass Du vielleicht gar nicht Matlab sondern eine Datenbank verwenden möchtest... Oder beides in Kombination.
Wenn ich den Datensatz so sehe, könnte es auch sein, dass Du vielleicht gar nicht Matlab sondern eine Datenbank verwenden möchtest... Oder beides in Kombination.
Von Datenbanken habe ich leider nicht viel Ahnung. Aber ich brauch später Berechnungen des Datensatztes und habe deswegen MATLAB gewählt..
Zitat:
Ein Hard- und/oder Softwareupgrade wäre für mich immer die letzte Alternative. Die meisten Probleme lassen sich mit ein bisschen Nachdenken auch auf der alten Hardware lösen.
Zumindet der Softwarupgrade ist für mich eig. kein Problem sondern nur einen Zeitfrage (ich habe Studentenlizenzen)
Zitat:
Was mich hier verwundert: du setzt delimiter auf ; als Trennzeichen scheint aber , zu fungieren.
Ja, das war vtl. ungünstig von mir. Ich hab das in 'Pseudo-MATLAB-Code' eingegeben, sprich ',' bedeutet neue Spalte und ';' neue Zeile.
In der Orginal csvDatei ist ';' der Zeichentrenner.
Zitat:
wenn du die Datei zippst, sollte es gehen.
Verstehe ich das richtig, man kann gezipted Datein direkt in MATLAB einlesen? Hast du wo das (Syntax) erklärt wird zur Hand? Ich habe nichts gefunden was mir weiterhilft.
Eilt aber nicht, denn:
Zitat:
Ist nicht immer möglich, aber wenn Du einfach nur einen Datensatz nach dem anderen Bearbeiten kannst, wäre das sicherlich die cleverste Variante.
Zitat:
Ansonsten würde auch ich das stückweise Einlesen vorschlagen.
Dann werde ich versuchen das umzusetzten. Ich habe ohnehin mehrere Datensätze und werde jetzt statt 1 Datensatz pro Jahr 12 (also einen pro Monat) einlesen, oder so ähnlich.
Wenn ich den Datensatz so sehe, könnte es auch sein, dass Du vielleicht gar nicht Matlab sondern eine Datenbank verwenden möchtest... Oder beides in Kombination.
Von Datenbanken habe ich leider nicht viel Ahnung. Aber ich brauch später Berechnungen des Datensatztes und habe deswegen MATLAB gewählt..
Die meisten Datenbanken können auch ein bisschen rechnen. Wenn Du die Daten mit Matlab aus der DB holst, müsstest Du dann nicht immer gleich die kompletten Zeilen im Speicher haben, sondern könntest auch auf einzelnen Spalten arbeiten. Das spart dann auch nochmal Speicher.
Falls Du überhaupt keinen Fuß auf den Boden bekommen solltest, kannst Du ja nochmal dran denken. So ein MySQL ist mit einem XAMPP ( https://www.apachefriends.org/de/ ) auch ratzfatz aufgesetzt und mit PHPMyAdmin kann man auch gut ein bisschen rumprobieren, wie das alles funktioniert. Für die Anbindung an Matlab habe ich gerade entdeckt, dass man wohl die Database-Toolbox braucht...
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.