Wenn ich bei prozentuale Anteile berechne und diese dann addiere erhalte ich ein ergebnis um 100,15% voran kann das liegen?
vielen dank im voraus!
Rundungsfehler bei Python?
Falls es der allgemeine Rundungsfehler ist kannst du hier http://www.python-forum.de/viewtopic.php?t=4563 alternativen sehen.
Allerdings ist der Rundungfehler ziemlich groß, also wie sieht der Quellcode aus ?
Allerdings ist der Rundungfehler ziemlich groß, also wie sieht der Quellcode aus ?
@DODO2000: Wenn es kein logischer Fehler im Programm ist, könnte es an Genauigkeitsproblemen bei der internen Darstellung von Fliesskommazahlen liegen. Das ist aber kein spezifisches Python-Problem -- das hättest Du in jeder Programmiersprach wenn Du Dort den selben Algorithmus implementierst und die selbe interne Darstellung von Fliesskommazahlen verwendet wird.
Code: Alles auswählen
with open("lm_origin-1.log","r") as input:
with open("benutzerdaten.txt","w") as output:
d={}
l=[]
gesamt=0
prozent=0
zahl=0
count=0
pend =0
for line in input.readlines():
if "Users of " in line:
prg=line.split()[2]
prg=prg[:-1]
if ", start " in line:
username=line.split()[0]
if username in d:
if prg in d[username]:
d[username][prg]+=1
count+=1
else:
d[username][prg]=1
count+=1
else:
d[username]={}
d[username][prg]=1
count+=1
for username in d:
l.append(username)
for prg in d[username]:
tmp=d[username][prg]
tmp=tmp/(count/100.0)*2
d[username][prg]=str(d[username][prg])+" ||| "+str(tmp)+"%"
pend=pend+tmp
count=0
l.sort()
for username in l:
print(username+" "+str(d[username]))
output.writelines(username+" "+str(d[username])+"\n")
count+=1
print(str(count)+" verschiedene Benutzer")
output.writelines(str(count)+" verschiedene Benutzer")
print "Gesamtprozente: " + str(pend) + "%"
output.close
input.close
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Na da hat sich aber einer Mühe gegeben, uns die wesentlichen Teile des Codes als lauffähiges Minimalbeispiel zu posten!
Die vermeindlichen close()-Aufrufe sind so übrigens falsch.
Davon abgesehen ist das beim Öffnen mit "with" ja gerade hinfällig und passiert automatisch. Das file Objekt ist an diesen Stellen bereits geschlossen.
Die vermeindlichen close()-Aufrufe sind so übrigens falsch.
Code: Alles auswählen
# ist nur das Objekt der Methode close
input.close
# so callt man es...
input.close()
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@DODO2000: Ohne jetzt im Detail das ganze nachvollzogen zu haben, denke ich Du addierst da zu früh und zu viele ungenaue Zahlen auf. Statt der Prozente würde ich zur Kontrolle lieber die absoluten Zahlen aufaddieren und schauen ob da das gleiche heraus kommt.
Sonstige Anmerkungen:
Der Aufruf von `readlines()` ist überflüssig, weil Dateiobjekte selbt schon "iterable" sind und zwar liefern sie die Zeilen. Insbesondere bei Logdateien kann das einen Unterschied machen ob man die Zeilenweise liest und verarbeitet oder eine potenziell grosse Logdatei mit `readlines()` komplett in den Speicher liest.
Namen wie `l` oder `d` sind eindeutig zu kurz und nichtssagend.
Ein paar mehr Lehrzeichen um Operatoren und das Arbeiten mit Zeichenkettenformatierung statt zusammensetzen per ``+`` würde das Ganze IMHO lesbarer machen.
Du greifst zu oft und zu tief mittels Schlüsselzugriff durch die Datenstruktur die an `d` gebunden ist. Statt über die Schlüssel zu iterieren um dann in der Schleife über den Schlüssel an den Wert zu kommen, kann man die Schleife auch gleich über die (Schlüssel, Wert)-Paare laufen lassen.
Das Zählen in der Schleife über `input` kann man mit einem `collections.defaultdict` drastisch vereinfachen.
`count` schein mir überflüssig zu sein. Das ist nach der ersten Schleife redundant zu ``len(d)`` und nach der zweiten redundant zu ``len(l)``.
Das Aufbauen von Zeichenketten über ``+`` in einer Schleife ist sehr ineffizient. Der idiomatische Weg ist das erstellen einer Liste die man dann am Ende mittels `str.join()` zusammenfügt.
Das in einer Datenstruktur Zahlen durch Zeichenketten ersetzt werden, halte ich für schlechten Stil. Die Objekte sollten zumindest den selben Ducktyp und die selbe Bedeutung behalten. Sonst kann man schnell mal den Überblick verlieren zu welchem Zeitpunkt welche Daten an *der gleichen* "Stelle" stehen.
Ich würde wahrscheinlich hier auch schon auf OOP setzen.
Sonstige Anmerkungen:
Der Aufruf von `readlines()` ist überflüssig, weil Dateiobjekte selbt schon "iterable" sind und zwar liefern sie die Zeilen. Insbesondere bei Logdateien kann das einen Unterschied machen ob man die Zeilenweise liest und verarbeitet oder eine potenziell grosse Logdatei mit `readlines()` komplett in den Speicher liest.
Namen wie `l` oder `d` sind eindeutig zu kurz und nichtssagend.
Ein paar mehr Lehrzeichen um Operatoren und das Arbeiten mit Zeichenkettenformatierung statt zusammensetzen per ``+`` würde das Ganze IMHO lesbarer machen.
Du greifst zu oft und zu tief mittels Schlüsselzugriff durch die Datenstruktur die an `d` gebunden ist. Statt über die Schlüssel zu iterieren um dann in der Schleife über den Schlüssel an den Wert zu kommen, kann man die Schleife auch gleich über die (Schlüssel, Wert)-Paare laufen lassen.
Das Zählen in der Schleife über `input` kann man mit einem `collections.defaultdict` drastisch vereinfachen.
`count` schein mir überflüssig zu sein. Das ist nach der ersten Schleife redundant zu ``len(d)`` und nach der zweiten redundant zu ``len(l)``.
Das Aufbauen von Zeichenketten über ``+`` in einer Schleife ist sehr ineffizient. Der idiomatische Weg ist das erstellen einer Liste die man dann am Ende mittels `str.join()` zusammenfügt.
Das in einer Datenstruktur Zahlen durch Zeichenketten ersetzt werden, halte ich für schlechten Stil. Die Objekte sollten zumindest den selben Ducktyp und die selbe Bedeutung behalten. Sonst kann man schnell mal den Überblick verlieren zu welchem Zeitpunkt welche Daten an *der gleichen* "Stelle" stehen.
Ich würde wahrscheinlich hier auch schon auf OOP setzen.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Nein, ich habe Dir nur einen schnell ersichtlichen Fehler in Deinem Code gezeigt - quasi als gratis Bonus DienstleistungDODO2000 hat geschrieben:das beantwortet jez aber nich meine frage oder? :K
Mir ging es darum, dass Du Kommentar los einfach Deinen Quellcode hier hinhaust. Wir können das so doch gar nicht laufen lassen (wir haben keine Datendatei usw) und müssen somit rein analytisch vorgehen. Das wird aber durch den ganzen Boiler Plate-Code erschwert, der sich ums Parsing dreht usw.
Du hättest doch einfach mal ein kleines Mini-Beispiel schreiben können, bei dem Du einfach eine Liste von Werten über Deine Formel aufsummierst.
Der Fehler verbirgt sich eben wohl genau hier drin:
Code: Alles auswählen
tmp=tmp/(count/100.0)*2
Also: Baue Dir doch mal ein Minimalbeispiel und zeige daran dokumentiert, was Du da ausrechnen willst. Ggf. kann man dann etwas finden, wie man den Rundungsfehler minimiert.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
also diese rechnung die ich da spaeter mit 2 multipliziert habe war nur ein versuch die ungenauigkeit zu umgehen aber : klappt nicht ich kann mir aber vorstellen das es an den string liegt weil diese ungenau umformen
@DODO2000: Hab's mal überarbeitet (ungetestet und natürlich immer noch mit Deinem Algorithmus):
Da waren am Anfang ja noch unnötige Zuweisungen (`zahl` und `gesamt`). Das fällt einem eher auf wenn man nicht alles am Anfang definiert, sondern erst dann wenn man es benötigt.
Erstell doch mal eine Beispiel-Log-Datei bei der man das Problem nachvollziehen kann. Je kürzer (und immer noch mit Problem) desto besser.
Code: Alles auswählen
from collections import defaultdict
from functools import partial
def main():
with open('lm_origin-1.log', 'r') as lines:
username2program_and_count = defaultdict(partial(defaultdict, int))
gesamt = 0
for line in lines:
if 'Users of ' in line:
prg = line.split()[2][:-1]
if ', start ' in line:
username = line.split()[0]
username2program_and_count[username][prg] += 1
gesamt += 1
pend = 0
username2program_and_output = defaultdict(dict)
for username, program2count in username2program_and_count.iteritems():
for prg, count in program2count.iteritems():
percent = count / (gesamt / 100.0) * 2
pend += percent
username2program_and_output[username][prg] = ('%d ||| %f%%'
% (count, percent))
with open('benutzerdaten.txt', 'w') as output:
for username, data in sorted(username2program_and_output.iteritems()):
print username, data
output.write('%s %s\n' % (username, data))
user_count = len(username2program_and_output)
print user_count, ' verschiedene Benutzer'
output.write('%d verschiedene Benutzer\n' % user_count)
print 'Gesamtprozente:', str(pend) + '%'
if __name__ == '__main__':
main()
Erstell doch mal eine Beispiel-Log-Datei bei der man das Problem nachvollziehen kann. Je kürzer (und immer noch mit Problem) desto besser.