Mittelwert und Sortieren aus einer Datei

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
snoop
User
Beiträge: 5
Registriert: Samstag 21. Dezember 2019, 16:09

Hallo,

leider bin ich ehr fachfremd und hänge an einen recht simplen Problem. (Zumindest hoffe ich das)
Meine vorliegende Datei sieht so aus (nur mit ca. 12 Millionen Zeilen):

Code: Alles auswählen

4479351.9200134277;5338396.7310028076;508.0069885254;147;155;166;1.0000000000;-0.0069885254;0.0108312042;-0.0076293945;0.0032043457
4479349.9380187988;5338399.2720031738;508.0079956055;149;159;169;1.0000000000;-0.0067749023;0.0072622220;0.0008544922;-0.0024719238
4479350.9820098877;5338397.3600006104;508.0020141602;143;152;163;1.0000000000;0.0010375977;0.0053485264;0.0045166016;0.0026702881  
4479352.1410064697;5338397.2279968262;508.0199890137;143;152;163;1.0000000000;-0.0059814453;0.0066083418;0.0026397705;-0.0009613037
4479351.3510131836;5338395.9920043945;508.0239868164;90;101;118;1.0000000000;0.0239868164;0.0861285925;-0.0383911133;-0.0732727051 
4479351.7740173340;5338395.9879913330;508.0199890137;152;162;174;1.0000000000;0.0099792480;0.0130636003;0.0082855225;-0.0015563965 
4479350.1510162354;5338399.8040008545;508.0320129395;162;170;180;1.0000000000;-0.0002441406;0.0081191240;-0.0047760010;-0.006561279
4479351.8720092773;5338400.7980041504;508.0870056152;154;162;173;1.0000000000;-0.0017395020;0.0097426260;-0.0054016113;-0.007919311
4479350.4960174561;5338399.6340026855;508.0339965820;161;167;177;1.0000000000;-0.0015869141;0.0043251603;0.0036773682;0.0016326904 
4479352.2170104980;5338400.8410034180;508.0870056152;151;161;171;1.0000000000;-0.0035705566;0.0056598592;0.0030822754;-0.0031280518
4479351.7390136719;5338397.8229980469;508.0230102539;155;163;173;1.0000000000;-0.0019531250;0.0144925080;-0.0141296387;0.0025634766
4479346.8240203857;5338400.9490051270;507.9620056152;146;154;165;1.0000000000;-0.0059814453;0.0063511948;-0.0005035400;-0.002075195
4479347.4800109863;5338400.1349945068;507.9660034180;155;163;174;1.0000000000;-0.0070190430;0.0096290698;-0.0039672852;0.0052642822
Hier möchte ich nun den Mittelwert der 8ten Spalte bilden und mir die Zahlen absteigend sortieren lassen.
Leider bekomme ich die Daten meiner Spalte nicht in eine Liste. Meine Überlegung war hier die Daten als float zu speichern.

Code: Alles auswählen

a = []
datei = open ("V3.csv","r")
for zeile in datei:
    spalte = zeile.split(";")
    a = spalte[7]
for element in a:
    print( float(element))
Jetzt bekomme ich aber schon hier einen Fehler:

Code: Alles auswählen

ValueError: could not convert string to float: '-'
Mir ist bewusst, dass das alles sehr stümperhaft wirkt (ist es auch). Aber vielleicht kann mir jemand weiterhelfen?
Streuni
User
Beiträge: 4
Registriert: Samstag 21. Dezember 2019, 16:06

Hi snoop!
Dein Problem ist glaube ich, dass du in Zeile 5 geschrieben hast:

Code: Alles auswählen

a = spalte[7]
Du willst a aber nicht neu definieren, sondern ihm ein Element hinzufügen. Dafür gibt es zwei einfache Möglichkeiten.
1.:

Code: Alles auswählen

a = a + [spalte[7]]
#andere Schreibweise:
a += [spalte[7]]
Diese Methode wird eher selten verwendet. Besser ist
2.:

Code: Alles auswählen

a.append(spalte[7])
Übrigens, wenn du wissen willst, was bei deinem vorherigen Programm passiert ist:
a war keine Liste, sondern ein String. Und zwar der Letzte String der 8. Spalte, also "-0.0070190430"
Wenn du nun durch a iterierst (for element in a), nimmt element die Werte "-", "0", ".", "0", "0", "7", "0", "1", "9", "0", "4", "3", "0" an. Und schon bei dem "-" kann es nicht zu float konvertiert werden.
Ich hoffe ich konnte helfen,
Streuni
Zuletzt geändert von Streuni am Samstag 21. Dezember 2019, 17:37, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Streuni: Die erste Variante sind zwei unterschiedliche Dinge und nicht einfach nur unterschiedliche Schreibweisen für das gleiche. Das erste funktioniert nicht weil man eine Liste und eine Zeichenkette nicht addieren kann:

Code: Alles auswählen

In [17]: a = a + "-0.0070190430"                                                
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-17-bca2a02606dd> in <module>
----> 1 a = a + "-0.0070190430"

TypeError: can only concatenate list (not "str") to list
Und die zweite Schreibweise hängt nicht *ein* Element an die Liste sondern erweitert die Liste um *alle* Elemente aus dem zweiten Argument, wozu das zweite Argument etwas iterierbares sein muss:

Code: Alles auswählen

In [18]: a += "-0.0070190430"                                                   

In [19]: a                                                                      
Out[19]: ['-', '0', '.', '0', '0', '7', '0', '1', '9', '0', '4', '3', '0']
Das ist warum man `append()` benutzt um ein einzelnes Element an eine Liste anzuhängen. Denn das tut was man will, im Gegensatz den den anderen beiden ”Varianten” die etwas anderes tun.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Streuni
User
Beiträge: 4
Registriert: Samstag 21. Dezember 2019, 16:06

@__blackjack__
Ups, da muss ich dir Recht geben. Ich meinte

Code: Alles auswählen

a += [spalte[7]]
Das sollte dann auch funktionieren (eigene Erfahrungen), aber a.append ist wie gesagt besser.
Sorry dafür, hätte genauer hingucken müssen,
aber danke, dass du mich drauf hingewiesen hast
Übrigens, nicht wundern, ich hab's geändert
Streuni
snoop
User
Beiträge: 5
Registriert: Samstag 21. Dezember 2019, 16:09

Super, vielen Dank an euch!

Code: Alles auswählen

datei = open ("V1.csv","r")

lines=0
for line in datei.readlines():
    lines+=1
print (lines)
    
a = []
c = []

datei = open ("V1.csv","r")

for zeile in datei:
    spalte = zeile.split(";")
    a.append(spalte[7])

b = ([(abs(float(i))) for i in a])

mittel = sum(b)/lines
print (mittel)
So funktioniert nun die Mittelbildung. Allerdings muss ich die Datei zweimal öffnen.. Ist das normal? Bzw. kann ich das geschickter Lösen?
Das Skript funktioniert leider auch nur bei einer keinen Beispielsdatei, bei meinen 12 Millionen Werten stürzt es ab..
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snoop: Natürlich geht das auch mit nur einmal öffnen der Datei. Du musst halt in einem Durchgang beide Aufgaben erledigen, das Zählen der Zeilen und das einlesen der Daten. Selbst in Deinem jetzigen Ansatz ist die erste Schleife überflüssig, denn was ist denn der Unterschied zwischen `lines` aus der ersten Schleife und der Länge der Liste `a`? Selbst im ersten Fall: `readlines()` liefert eine Liste. Die hat eine Länge die man effizienter ermitteln kann als alle Elemente durchzu gehen und für jedes 1 zu addieren.

Wobei jetzt mal ernsthaft über Namen reden müssen: `a` ist ein schlechter Name. Wie so ziemlich jeder einbuchstabiger Name, mit Ausnahme von `i` oder `j` für einen Laufindex und `x`, `y` für Koordinaten. Namen sollen dem Leser vermitteln was der Wert bedeutet. `a` tut das so gar nicht.

Aber auch längere Namen in dem Programm sind nicht gut gewählt. Hinter `lines` würde man die Zeilen selbst vermuten nicht die Anzahl der Zeilen. Und `spalte` steht nicht für eine einzelne Spalte sondern für *alle* Spalten.

`c` wird definiert, aber nirgends verwendet.

Dateien die man öffnet, sollte man auch wieder schliessen. Wo möglich sollte man die ``with``-Anweisung dafür verwenden.

Letztlich ist nicht nur das zweimalige öffnen und verarbeiten der Datei ineffizient, sondern um die Aufgabe zu lösen, braucht man den Inhalt der Datei nicht komplett im Speicher. Auch ein einzelner Wert pro Zeile nicht. Wenn Du das manuell lösen würdest, würdest Du ja auch nicht anfangen erst einmal eine Liste mit allen Zahlen aus der 8. Spalte aufzuschreiben. Und dann aus der Liste wieder eine neue Liste mit den ganzen Absolutwerten zu erstellen. Du würdest gleich anfangen gleichzeitig die Zeilen zu zählen und auch gleich die Absolutwerte der 8. Spalte zu *einem* Wert zu addieren, *während* Du die Eingabedaten durchgehst. Das sollte auch das Programm machen. Dann sehe ich keinen Grund warum das abstürzen sollte.

Was bedeutet abstürzen denn hier genau? Wenn das Programm eine Ausnahme liefert, solltest Du die auch komplett mit Traceback zeigen. Sonst können wir nur raten woran es scheitert.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

Und wenn man das ernsthaft für 12 Millionen Zeilen machen will, dann schriebt man das nicht alles selbst, sondern löst das mit zwei Zeilen numpy.
snoop
User
Beiträge: 5
Registriert: Samstag 21. Dezember 2019, 16:09

Möchte ich die Werte direkt als Betrag hinzufügen bekomme ich den Fehler:

Code: Alles auswählen

deltaZ.append([(abs(float(i))) for i in spalten[7]])
ValueError: could not convert string to float: '-' 
oder bei weiteren Versuchen die Liste

Code: Alles auswählen

[<generator object <genexpr> at 0x031AEA70>, <generator object <genexpr> at 0x03192B50>, <generator object <genexpr> at 0x031BCDF0>, <generator object <genexpr> at 0x031BCE60>, <generator object <genexpr> at 0x031BCE28>, <generator object <genexpr> at 0x031BCE98>]
Ich dachte, dass ich dies umgehen kann indem ich zuerst eine Liste anlege und in einer neuen dann den Betrag abspeichere (bei der Datenmenge tatsächlich nicht besonders klug).

Absturz im Sinne von "keine Rückmeldung" und folgend die Schließung des Fensters.
Leider kenne ich mich mit numpy noch weniger aus. Ich werde versuchen mich reinzulesen... Sehr viel effizienter kann das dort aber doch auch nicht gehen? (also wenn ich mal das Erstellen der ersten Liste mit den Absolutwerten gemeistert habe)
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snoop: Das Problem mit dem "-" hat Streuni ja schon erklärt. Du versuchst da über etwas zu iterieren was Du als ganzes in eine Zahl umwandeln musst und nicht die einzelnen Zeichen davon.

Welches Fenster schliesst sich da? Wie startest Du das? Wenn Du es in einer offenen Konsole startest dann schliesst die sich auch nicht am Ende und Du kannst die Ausnahme lesen die da ausgegeben wird.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Benutzeravatar
ThomasL
User
Beiträge: 1378
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Na weil Weihnachtszeit ist hier mal ein simples Beispiel wie man das mit numpy macht.
Alles weitere findest du hier: https://numpy.org/doc/

Code: Alles auswählen

import numpy as np

# Einlesen der Datei
data = np.loadtxt('V3.csv', delimiter=';', dtype=np.float64)

# Ausgabe Spalte 8
print(data[:,7])

# Mittelwert der Spalte 8
print(data[:,7].mean())

# Erzeugen einer sortierten Kopie von Spalte 8 und Ausgabe
col7_sorted = np.sort(data[:,7])
print(col7_sorted)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
snoop
User
Beiträge: 5
Registriert: Samstag 21. Dezember 2019, 16:09

@__blackjack__ Entschuldige, dass ich so spät reagiere! Ich war mir sicher ich hätte geantwortet (das hab ich wohl geträumt?) :D

Genau das Problem mit den umwandeln in "float" kenne ich. Nur kann ich das ja ohne erstellen einer ersteln Liste nicht umgehen.. Daher hab ich ja immer zwingend die zwei Listen?
Ich erstelle in Python IDLE eine neue Datei und diese läuft dann über Shell. Hier kommt dann eben "keine Rückmeldung" und dann "das Programm reagiert nicht mehr". Hier könnte ich dann theoretisch bis nach Weihnachten warten, nach mehreren Minuten sage ich dann "Programm schließen" Das wars dann... Evtl machen aber auch meine NaN Werte Probleme und deshalb funktioniert es nicht?

@ThomasL vielen Dank! ich werde mich über die Feiertage einmal einlesen.

Das Problem habe ich momentan durch ein seperates Statistik Programm (IBM SPSS) umgangen. Hier können auch meine NaN Werte direkt gefiltert werden. Um dieses Problem in Python zu lösen würde mir nämlich auch nichts besseres als eine weitere Liste einfallen.
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snoop: Natürlich kannst Du das Problem mit dem `float()` ohne erstellen einer Liste ”umgehen”. Das Problem selbst entsteht ja gerade erst weil Du die Zeichenkette in eine Liste umwandelst und dann versuchst die einzelnen Zeichen in Gleitkommazahlen zu wandeln statt die Zeichenkette in eine Gleitkommazahl zu wandeln. Also ist die Lösung davon schon mal eine Liste (pro Wert) weniger. Und dann besteht kein Grund alle Werte als Zeichenketten in eine Liste einzulesen um dann eine weitere Liste mit den Zeichenketten in Zahlen umgewandelt zu erstellen. Man kann da auch gleich jeden eingelesenen Wert in eine Zahl umwandeln und *einer* Liste hinzufügen.

Von NaN-Werten war bisher ja nicht die Rede. Wenn die als "NaN" da stehen kommt `float()` damit klar (ohne auf Gross-/Kleinschreibung zu achten):

Code: Alles auswählen

In [25]: x = float("NaN")                                                       

In [26]: x                                                                      
Out[26]: nan

In [27]: import math                                                            

In [28]: math.isnan(x)                                                          
Out[28]: True
Wobei man das aber auch auf Zeichenkettenebene schon raus filtern kann.

Bei NaN-Werten wäre in deinem ersten Ansatz ja auch das zählen der Zeilen schon falsch denn die NaNs zählen ja nicht zur Gesamtzahl beim Durchschnittswert.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Benutzeravatar
ThomasL
User
Beiträge: 1378
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Aha, nun kommt er mit der Info, dass in den Daten auch NaNs vorhanden sind.
Ist ja nicht so als das das im Vorfeld eventuell erwähnenswert gewesen wäre.

Wenn du solche Daten auch in Python produktiv bearbeiten willst, solltest du dich in das Modul pandas einarbeiten.

https://pandas.pydata.org/pandas-docs/s ... index.html

https://youtu.be/5rNu16O3YNE
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei `numpy.loadtxt()` mit "NaN" als NaN-Wert auch klar kommt, genau wie `float()`. `numpy.genfromtxt()` ist da noch etwas flexibler weil man da angeben kann was fehlende Werte ausmacht und durch was die ersetzt werden sollen.

In beiden Fällen würde `usecols` beim Einlesen Sinn machen wenn man tatsächlich nur eine Spalte verarbeiten möchte.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
snoop
User
Beiträge: 5
Registriert: Samstag 21. Dezember 2019, 16:09

@_blackjack_
Alles klar, das werde ich nochmal versuchen.
Um die NaN Werte zu umgehen hatte ich bisher nur an das

Code: Alles auswählen

L=deltaZ[math.isnan(deltaZ)==False]
print(L)
gedacht. Also dachte ich "toll wieder eine Liste".
Leider bin ich tatsächlich komplette Anfängerin und hatte die Hoffnung mit meinem kleinen Basic Wissen zu einem brauchbaren Ergebnis zu kommen.
Wenn ich mal eins/zwei Tage habe werde ich mich definitv tiefer einarbeiten.
Das mit den Zählen ist richtig. Allerdings habe ich selbst nicht damit gerechnet NaN-Werte zu finden (die Daten kommen aus einem Punktwolkenvergleich). Letztendlich verändert ein Teiler, der evtl. 50 größer ist als tatsächlich stimmig, mein Ergenis in der Genauigkeit nicht ausschlaggebend. Dennoch möchte ich jetzt natürlich das bestmöglichste Ergebnis erzielen und werde versuchen das zu umgehen. "Usecols" klingt tatsächlich allgemein sinnvoll für mich. Danke!

@ThomasL
Entschuldige. Das wäre tatsächlich erwähnenswert gewesen. Leider bin ich selbst erst durch Bearbeitung in einen weiteren Programm darauf gestoßen..
Pandas setze ich mit auf meine Liste. Danke!

Zu Weihnachten nehme ich mir also numpy und pandas vor!
Benutzeravatar
__blackjack__
User
Beiträge: 14032
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snoop: Vergleiche mit literalen `True` oder `False` Werten macht man in aller Regel nicht. Da kommt ja eh nur wieder ein Wahrheitswert bei heraus, entweder der gleiche den man sowieso schon hatte vor dem Vergleich, oder dessen Gegenteil. Dafür gibt es ``not`` für einzelne Wahrheitswerte oder den ``~``-Operator um ein ganzes Numpy-Array elementweise zu negieren.

Deine Zeile funktioniert aber nicht, denn `math.isnan()` kann nur Skalarwerte und das geht dann nur wenn das Array genau *ein* Element enthält. Das wäre also eher

Code: Alles auswählen

values_without_nan = delta_z[~numpy.isnan(delta_z)]
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten