Forum: PC-Programmierung CSV Datei: Zahlen Genauigkeit reduzieren 3.00000001 -> 3.00E+0


von Moritz (Gast)


Lesenswert?

Hallo,
ich habe CSV Dateien die eine große Dateigröße haben und deshalb schwer 
zu verarbeiten sind.

Die Daten sind im Format (beispielhaft)
1
X,Y,Z
2
1.00010001,  5.003, 1.000500001E-20
3
1.99999999, 10.001, 2.020100005E-21
4
3.02000001, 14.999, 3.000000011E-20
(Leerzeichen sind in der Datei nicht vorhanden, nur zur besseren 
Lesbarkeit)

Dh. die Zahlen haben einerseits sehr viele Nachkommastellen und sind zum 
Teil in E+XX Schreibweise.

Ich möchte jeztzt ein Skript schreiben, dass die Datei einliest, alle 
Zahlen auf eine vorgegebene Anzahl von Dezimalstellen rundet (bzw. 
abschneidet) und dann in eine neue Datei speichert.

Die Ausgabe sollte z.B. bei "3 Stellen Genaugigkeit" so aussehen:
1
X,Y,Z
2
1.00,  5.00,    1.00E-20
3
2.00,  1.00E+1, 2.00E-21
4
3.02,  1.50E+1, 3.00E-20
(ebenfalls Beispielhaft, ob alle Zahlen ein E+XX Format bekommen ist 
egal. Leerzeichen nur zur besseren Lesbarkeit eingefügt)

Danke schonmal
Moritz

PS: Skriptsprache ist egal, am liebsten etwas das unter Windows+Linux 
läuft (z.B. Python?)

von Achim (Gast)


Lesenswert?

Wo ist jetzt die Frage oder das Problem?

von Moritz (Gast)


Lesenswert?

Achim schrieb:
> Wo ist jetzt die Frage oder das Problem?

Ich suche ein Skript mit dem man die CSV Daten einlesen, Anzahl Stellen 
der Zahlen reduzieren und wieder abspeichern kann.

Danke!

von Tangens (Gast)


Lesenswert?

Regulärer Ausdruck + eine Programmiersprache deiner Wahl.

von Tasg (Gast)


Lesenswert?

Gibt es in Tabellenkalkulationsprogrammen keine Funktion zum RUNDEN?! 
Probiers mal mit LibreOffice Calc, das ist umsonst.

von Markus F. (mfro)


Lesenswert?

Dein Skript heißt LibreOffice.

Dort kann man Tabellen so als .csv exportieren, wie sie auf dem 
Bilschirm formatiert dargestellt sind.
Also einmal importieren, so formatieren, wie Du's haben willst und beim 
Wiederexportieren den Knopf "Zellinhalt wie angezeigt speichern" 
drücken.

Ob das in Excel auch geht, weiß ich nicht.

von Moritz (Gast)


Lesenswert?

Danke schonmal für die Tipps.

Ich suche nach einer automatisierbaren Lösung, d.h. nicht Excel.

Im Idealfall kann ich das Skript per Kommandozeile starten, z.b.
1
convertSkript input.csv output.csv

Und es erstellt eine neue Datei mit reduzierter Genauigkeit der Daten.

Grüße
Moritz

von Dieter F. (Gast)


Lesenswert?

Moritz schrieb:
> Ich suche nach einer automatisierbaren Lösung, d.h. nicht Excel.
>
> Im Idealfall kann ich das Skript per Kommandozeile starten, z.b.
> convertSkript input.csv output.csv
> Und es erstellt eine neue Datei mit reduzierter Genauigkeit der Daten.

Da musst DU wohl was tun ...

von Tasg (Gast)


Lesenswert?

Und wo ist jetzt das Problem? Jemand der ein bisschen Coden kann, kann 
sich das doch schnell in 15 Minuten (z.B. in Python) zusammenhacken.

von Tasg (Gast)


Lesenswert?

Foren wie diese sind eigentlich dafür gedacht, Leuten, die ein Problem 
mit irgendetwas haben, auf die Sprünge zu helfen oder Tipps zu geben. 
Das hier dient nicht dazu, für Lau Programme erstellt zu bekommen.

von Hilfreiche Person (Gast)


Lesenswert?

Hier eine Lösung mit Perl:
1
> cat csv
2
X,Y,Z
3
1.00010001,  5.003, 1.000500001E-20
4
1.99999999, 10.001, 2.020100005E-21
5
3.02000001, 14.999, 3.000000011E-20
6
7
> cat csv | perl -pe 's/([0-9]+\.[0-9]+([eE][ +-][0-9]+)?)/sprintf("%0.3g", $1)/ge'
8
X,Y,Z
9
1,  5, 1e-20
10
2, 10, 2.02e-21
11
3.02, 15, 3e-20

von W.A. (Gast)


Lesenswert?

Moritz schrieb:
> Ich suche nach einer automatisierbaren Lösung, d.h. nicht Excel.

Makros funktionieren bei dir nicht? Einmal vorgeturnt und ...

von Vielleicht hilfreich (Gast)


Lesenswert?

Hier eine Lösung in C# (sollte in jede Sprache übertragen werden können)
1
static void Main(string[] args)
2
        {
3
            Regex regex = new Regex((@"-?\d +.?\d *)(E[+-]\d +) ?"));
4
            var temp = File.ReadAllText(args[0]);
5
            regex.Matches(temp).Cast<Match>().Select(match => match.Value).ToList().ForEach(match => {
6
                temp.Replace(match, Math.Round(Convert.ToDouble(match), Convert.ToInt32(args[2])).ToString());
7
            });
8
            File.WriteAllText(args[1], temp);
9
        }

Kann somit über die Kommandozeile mit <input.csv> <output.csv> <Stelle 
auf die gerundet werden soll> aufgerufen werden.

von Markus F. (mfro)


Lesenswert?

Moritz schrieb:
> Ich suche nach einer automatisierbaren Lösung, d.h. nicht Excel.

Deswegen habe ich ja auch LibreOffice vorgeschlagen. Das läßt sich mit 
Python ganz prima skripten.

von Sebastian S. (amateur)


Lesenswert?

Wozu das Ganze?

Was mich interessiert ist die Ausgabe und nicht das Rohformat!

Runde so viel Du willst bei der Ausgabe – von mir aus schneide alles was 
übersteht ab - aber lass die Rohdaten in Ruhe.

von Sebastian S. (amateur)


Lesenswert?

Ich Vergaß (doppelt)!

Vor kurzem habe ich einen Artikel gelesen, nachdem 30% (man höre und 
staune) aller in (vom allem von Microsoft) Tabellen vorhandenen Daten, 
grobe Fehler enthalten. Vor allem durch nachträgliche "Verbesserungen". 
Oft beim Versionssprung automatisch durchgeführt!

Wenn Du Dich persönlich hier einreihen möchtest: Hau rein!

von Norbert (Gast)


Lesenswert?

Tasg schrieb:
> Probiers mal mit LibreOffice Calc, das ist umsonst.

Da muss ich widersprechen,
LibreOffice ist nicht umsonst, es ist kostenlos!

von Moritz (Gast)


Lesenswert?

Vielen Dank für die Hilfe, insbesondere mit dem regulären Ausdruck. 
Besten Dank.

PS: Ein Forum lebt vom geben und nehmen, deshalb freut es mich dass eine 
funktionsfähige Lösungen von Personen gepostet werden für die die 
Aufgabe leicht lösbar ist. Wenn die Person (ich) der damit Arbeit 
abgenommen wurde dann im Umkehrschluss in anderen Threads ebenfalls 
selbstlos Hilfe anbietet und anderen Zeit erspart haben alle profitiert. 
Insofern kann ich die Nörgler nicht verstehen und mich umsomehr bei den 
aktiven des Forums bedanken!

Grüße

Hilfreiche Person schrieb:
> Hier eine Lösung mit Perl:> cat csv
> X,Y,Z
> 1.00010001,  5.003, 1.000500001E-20
> 1.99999999, 10.001, 2.020100005E-21
> 3.02000001, 14.999, 3.000000011E-20
>
>> cat csv | perl -pe 's/([0-9]+\.[0-9]+([eE][ +-][0-9]+)?)/sprintf("%0.3g",
> $1)/ge'
> X,Y,Z
> 1,  5, 1e-20
> 2, 10, 2.02e-21
> 3.02, 15, 3e-20

Vielleicht hilfreich schrieb:
> Hier eine Lösung in C# (sollte in jede Sprache übertragen werden können)
> static void Main(string[] args)
>         {
>             Regex regex = new Regex((@"-?\d +.?\d *)(E[+-]\d +) ?"));
>             var temp = File.ReadAllText(args[0]);
>             regex.Matches(temp).Cast<Match>().Select(match =>
> match.Value).ToList().ForEach(match => {
>                 temp.Replace(match, Math.Round(Convert.ToDouble(match),
> Convert.ToInt32(args[2])).ToString());
>             });
>             File.WriteAllText(args[1], temp);
>         }
>
> Kann somit über die Kommandozeile mit <input.csv> <output.csv> <Stelle
> auf die gerundet werden soll> aufgerufen werden.

von Jim M. (turboj)


Lesenswert?

Moritz schrieb:
> ich habe CSV Dateien die eine große Dateigröße haben und deshalb schwer
> zu verarbeiten sind.

Ganz sicher? CSV wird normalerweise mit Interface-geschwindigkeit 
eingelesen.
D.h. Du würdest die Änderungen nur auf einem ganz lahmen NAS oder 
uraltem USB Stick merken, und das auch nur bei Dateien in GB Größe.

Ich sehe da überhaupt kein Einsparpotential: Die Konvertierung dauert 
viel länger als Du durch das ein ganz kleines bißchen schnellere 
Einlesen sparen wirst.

Drei signifikate Stellen sind übrigens nur ca. 10 Bit, gute ADCs gibt es 
mit 12, 14,..,24 Bit je nach Anwendung. Falls die Daten also nicht aus 
einem Arduino rausfallen wirfst Du hier Auflösung weg.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.