Probleme beim Runden (pandas.sum)

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

Hallo,

ich habe folgendes Problem:

Ich erstelle ein Dataframe und filtere anhand von bestimmten Kriterien nach Datensätzen. Diese Datensätze haben Werte für KW (3 Nachkommastellen) und Euro (2 Nachkommastellen). Solange ich keine Summierung drüber laufen lasse bleiben die Nachkommastellen bestehen. Wenn ich aber den Sum-Befehl über die Dataframes laufen lasse habe ich plötzlich 14 Nachkommastellen, was das Gesamtergebnis verfälscht.

Hier mal ein Auszug aus dem ursprungs-dataframe:

Code: Alles auswählen

           MATERIAL KW_WERT NETTO_EURO                 TA  
0            B60ETS    0.15       18.9                SDH  
1            B60ETS   0.145      18.27                SDH  
2            B60ETS   0.145      18.27                SDH  
3            B60ETS    0.15       18.9                SDH  
4            B60ETS    0.15       18.9                SDH
hier der Summen-Befehl für Pandas:

Code: Alles auswählen

data_kl2m_bw_EUR = data_kl2m_bw['NETTO_EURO'].sum()
hier dann die Ergebnisse für die Summen:

390.05799999999925
39731.49999999992
508.10499999999786
78528.43000000018

Wie kann ich das verhindern? Ich brauche nämlich die exakten Summen und nicht die durch die zusätzlichen Nachkommastellen verfälschten.

Wäre schön, wenn jemand eine Idee hätte.

lg

Damian
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@KrachBumm: Du hast ein falsches Verständnis von Fließkommazahlen. Die Summen sind so exakt, wie sie Deine CPU rechnen kann. Eine Zahl wie 18.27 kann halt im Binärsystem nicht exakt dargestellt werden. Den viel größeren Fehler machst Du bereits beim Ermitteln der KW_WERTe, da diese statt auf 10 Nachkommastellen nur auf 2 Nachkommastellen exakt sind. Verabschiede Dich also von der Vorstellung, dass es bei Zahlen im richtigen Leben (außerhalb der Mathematik) so etwas wie exakt gibt.

Zu Deinem Problem: Du gibst die Zahlen im falschen Format aus:

Code: Alles auswählen

print "Summe NETTO_EURO: {.2f}".format(data_kl2m_bw_EUR)
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

Danke erstmal für die Erläuterung.

Hier geht es leider nicht um Werte, die von mir ermittelt werden, sondern um Werte, die mir zur Verfügung stehen und weiterverrechnet werden müssen. Das heisst konkret, ich kann an den Ausgangswerten nichts ändern. Und geläufig sind nunmal bei Euro 2 Stellen und bei KW 3 Stellen nach dem Komma.

Hier meinte ich auch mit exakt nicht die Verarbeitung durch meine CPU, sondern exakt von meiner Sicht aus. Entschuldigung dafür, wenn ich das falsch ausgedrückt hatte.

Meine Frage bezog sich wirklich darauf, dass mir die Zahlen, wie in einem Taschenrechner aufsummiert werden. Ich werde natürlich noch nach Wegen suchen das zu lösen!

Danke ;)
BlackJack

@KrachBumm: Ich weiss nicht ob Du das richtig verstanden hast. Du hast in der Datei vielleicht 18.27 stehen, das hat im Rechner dann aber mehr als zwei Nachkommastellen:

Code: Alles auswählen

In [4]: '{0:.50f}'.format(18.27)
Out[4]: '18.26999999999999957367435854393988847732543945312500'
Die 18.27 wird als Gleitkommazahl in der binären Darstellung so gut angenähert wie es eben geht. Exakt 18.27 geht als `float` halt nicht.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@KrachBumm: Dir ist es vielleicht nicht aufgefallen, aber die Lösung habe ich Dir schon präsentiert.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

@Sirius: Doch das habe ich gesehen, das ist aber nicht das was ich brauche. Er rundet bei deiner Lösung ja nur das Ergebnis auf die zwei Nachkommastellen. Das Problem was ich aber habe ist, dass schon innerhalb der Liste die Werte mit 14 Nachkommastellen addiert werden und somit die Summe schon gar nicht stimmt. Ich hoffe, dass ich das jetzt noch bischen besser erklären konnte.

@BlackJack: Doch das habe ich auch verstanden, ich muss aber jetzt trotzdem einen Weg finden um annähernd an die Ergebnisse zu kommen.

Allgemein war meine Idee noch, die Werte innerhalb des Dataframe mit 1000 zu multiplizieren um mit Integerwerten zu rechnen. Was haltet ihr von dieser Lösung?
BlackJack

@KrachBumm: Die Lösung um annähernd an die Ergebnisse zu kommen hat Sirius3 schon genannt. Überleg mal wie gross die Abweichung ist und wie viele Zahlen man addieren müsste, so dass in der dritten Stelle nach dem Komma ein falsches Ergebnis entstehen würde.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@KrachBumm: wie BlackJack schon geschrieben hat, ist die interne Darstellung nie auf drei Stellen gerundet. Das ist auch völlig egal, solange Du nicht mit mehr Geld rechnest, als das Bruttoinlandsprodukt von Deutschland.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

@BlackJack: Ich rechne mit ca. 400000 Datensätzen und sehe die Abweichung. Ich erstelle ein Tool für die Berechnung der Faktura. Das bedeutet, dass eine Kollegin diese bisher per Hand über zwei Tage mühsam zusammengerechnet hat. Das Tool macht das natürlich viel schneller. Ich probiere bei der Berechnung schon errechnete Werte aus. Und die Abweichung hier liegt in der Summe bei ca. 60 KW, was umgerechnet in der Summe einen Unterschied von 15.000 Euro macht. Dieser Gap ist zuviel. Deswegen reite ich so auf den Werten rum. Sorry für die Ausdrucksweise.

Aber ich danke euch für eure Mühe! Ich habe das grundlegende Problem in der Sache verstanden ;)
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@KrachBumm: Dann willst Du möglicherweise nicht Pandas nehmen, sondern Dir eine Lösung mittels Dezimal erarbeiten. Dieser Datentyp ist genau für solche Anwendungen gedacht.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@KrachBumm: wie hast Du denn herausgefunden, dass die Summe um 60kW abweicht? Ich glaube kaum, dass das an den Rundungsfehlern von Fließkommazahlen liegt, da bei 4000000 Zahlen noch mindestens 6 signifikante Nachkommastellen übrig bleiben, was also nach Rundung maximal eine Differenz von 1 Cent ergeben dürfte. Eher weniger.

Wenn Du mit den von Hand gerechneten Zahlen vergleichst, würde ich eher dort den Fehler suchen.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

@Sirius: Die Datensätze, die ich aufsummiere teilen sich auf ca. 20 größere Blöcke auf. Meine Angaben sind schon in KW, da ist eine Differenz in dieser Größe schnell erreicht. Die vom Tool ausgegebenen Werte sind ja nah an den errechneten Werten dran. Aber die Summe dieser kleinen Differenzen beträgt eben 60 KW. Ich habe das auch mit anderen Daten so gerechnet und die Abweichung bleiben annähernd gleich (natürlich ist eine Abweichung über die Jahre zu sehen, was aber dem Zuwachs über die Jahre geschuldet ist) und gehe ich mal von einer Abweichung an der zweiten Nachkommastelle aus, dann komme ich auf einiges mehr als du mir vorrechnest. Oder verstehe ich hier was falsch?

Das erkennt man ja schon an dem Beispiel von BlackJack. 18.27 ist 18,26... und verallgemeinere ich der Einfachheit halber dies auf die gesamten 400000 (+-20000) Datensätze komme ich auf eine mögliche Differenz von 4000... Oder sehe ich das falsch?

Wie gesagt ich bin kein Experte... ich gehe von meinem Verstehen der Zahlenwelt aus. Falls ich mich hier irre belehrt mich bitte eines besseren.
BlackJack

@KrachBumm: Ich denke da siehst Du etwas falsch.

Code: Alles auswählen

In [29]: a = 18.27

In [30]: A = 0

In [31]: for _ in xrange(400000):
    ...:     A += a
    ...: 

In [32]: '{0:.2f}'.format(A)
Out[32]: '7308000.00'
Und das ist genau das Ergebnis was da raus kommen sollte. Deine Punkte bei 18.26… suggerieren, dass der Wert mit dem gerechnet wird um 0.01 abweicht, das tut er aber nicht, die Abweichung ist *viel* kleiner, nämlich so ungefähr 0,0000000000000004263256414560601115226745605. Und da dauert das echt lange bis sich das beim aufaddieren in der zweiten oder auch dritten Stelle nach dem Komma bemerkbar macht.

Edit: Du brauchst 23.456.248.059.221 Additionen bis sich das soweit aufaddiert hat, dass die zweite Nachkommastelle erreicht wird.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Es gibt keinen Unterschied zwischen 18.27 und 18.26 sondern zwischen 18.27000000000000000000000000000000000000000000000000 und 18.26999999999999957367435854393988847732543945312500.
Und da ist die Differenz eben nur 0.00000000000000042632564145606011152267456054687500 was mit 40000000 multipliziert 0.000000017053025658242404e ergibt, also keine Kilowatt sondern nur 17 µW.

Daher bleibt die Frage, wer macht welchen Fehler. Das Aufsummieren kann diesen Fehler nicht machen, also muß er irgendwo anders liegen. Welche Zahlen vergleichst Du also genau? Sind sie aus der selben Quelle? Wo wird wie gerundet? Sind die Daten vollständig?

Wenn irgendeine Quelle Daten mit mehr als 2 Nachkommastellen hat, dann kannst Du mit der Text-Datei, die auf 2 Stellen gerundet ist, schon mit ~ 24000 Werten 60kW Differenz erreichen. Das stimmt dann mit Deinen 20-Blöcken a 20000 Zahlen gut überein. Das liegt dann aber nicht an Python sondern an dem Programm, das die Text-Datei schreibt.

Mit anderen Worten, Deine Eingangsdaten sind für den Papierkorb.

Um da weiter zu kommen, brauchen wir etwas mehr Kontext: Wer produziert die Text-Dateien? Was willst Du mit den Zahlen anfangen? Welche Größenordnung an Fehler stört Dich wirklich?
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

ok wieder was gelernt! Danke!

Sirius hier die Antworten auf deine Fragen:

Die Daten kommen alle aus der gleichen Quelle als xlsx-Datei. Die bisherigen Berechnungen hat auch die gleiche Kollegin gemacht. Die Kollegin, die die Daten stellt kenne ich nicht. Die Kollegin, die die Berechnungen macht sitzt gegenüber von mir und macht das seit jeher händisch.

In den Quelldaten sind nur 3 Nachkommastellen bei KW und 2 Nachkommastellen in Euro. Da gibt es keine Abweichung, das habe ich schon überprüft. Ich kann euch diese Daten aber auch nicht komplett zeigen, das geht leider aus Geheimhaltungsgründen nicht.

Aus diesen Zahlen wird fakturiert bzw. ist die Aufsummierung dieser Blöcke, in diesem Fall sind das Technikarten, aus denen später prozentuale Schlüssel für eine Kostenverteilung errechnet werden. Soviel zur Erläuterung wozu ich diese Zahlen brauche. Aber dieser Unterschied ist nicht akzeptabel, da dann später immer wieder Unterschiede entstehen, die von der Berechnung abweichen.

Hier rundet meine Kollegin nicht. Sie hat die Zahlen einfach per Hand aufsummiert und ist dann auf die Zahlen gekommen. Habe ich die Ursprungsdaten per Hand nach den Technikarten gefiltert bin ich auf die gleichen Summen gekommen, wie meine Kollegin.

Und ob nun die Eingangsdaten für den Papierkorb sind oder nicht: Ich kann die Eingangsdaten nicht beeinflussen, sondern muss diese so verarbeiten wie sie eben reinkommen. Da ist so eine Aussage nicht hilfreich.

Wenn ihr für meine Problemstellung erstmal keine Lösung habt ist das ja nicht wild. Ich frage ja nur an. Ansonsten muss ich einfach alternativen finden.

Vielen Dank aber für die Erläuterungen ;)
BlackJack

@KrachBumm: Was heisst denn sie addiert händisch wenn die Daten in Excel-Tabellen vorliegen? Sie hat sich tatsächlich Stift und Papier genommen und mehrere zehntausend Einzelwerte addiert? Und Du hast das dann auch gemacht um das Ergebnis nachzuprüfen? Das kann ich mir irgendwie nur schwer vorstellen.

Kann es sein, dass die Daten in den Tabellen doch *mehr* Nachkommastellen haben und nur 2 bzw. 3 davon *angezeigt* werden? Kannst Du statt nur das Endergebnis zu prüfen mal Zwischenergebnisse prüfen um der Abweichung auf die Spur zu kommen? Wie gesagt, diese Abweichung lässt sich mit den bisherigen Informationen *nicht* durch Gleitkommazahlen erklären. Da muss irgend ein anderer Unterschied in der Art und Weise der Berechnung existieren.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

@BlackJack:

Die Daten liegen ja in Excel-Dateien vor und auch wenn ich in Excel "nur" 3 Nachkommastellen in der Zelle sehe, kann ich darin immernoch überprüfen, ob mehr Stellen vorhanden sind. Das habe ich gemacht.

Nein und natürlich hat keiner von uns beiden per Hand 400000 Werte aufsummiert. Sie hat das vorher über gegebene Excelfunktionen gemacht. Natürlich kann auch hier der Fehler liegen. Das will ich gar nicht bestreiten. Auch habe ich Zwischenergebnisse gebildet, um die Summen zu überprüfen. Diese Stimmen auch bis zu dem Punkt an dem ich den Summenbefehl von Pandas ausführe. Danach entstehen die Abweichungen.

Ich weiss langsam nicht mehr wie ich das erklären soll ^^
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

KrachBumm hat geschrieben:Die Daten liegen ja in Excel-Dateien vor und auch wenn ich in Excel "nur" 3 Nachkommastellen in der Zelle sehe, kann ich darin immernoch überprüfen, ob mehr Stellen vorhanden sind. Das habe ich gemacht.
Und was war das Ergebnis? Sind nun nur 3 Nachkommastellen im Excel oder mehr?
Btw: Pandas kann auch direkt Excel lesen.
KrachBumm
User
Beiträge: 18
Registriert: Mittwoch 27. Juli 2016, 07:50

@Sirius: In Excel sind es nur 3 bzw 2 Nachkommastellen. Und meine Kollegin möchte das auch so gerechnet haben. Ich lese auch die Excel über pandas ein, soweit bin ich auch schon gekommen ^^
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@KrachBumm: nochmal als Zusammenfassung, in Excel werden Zahlenreihen erst gefiltert und dann summiert. Wie sieht die Filterung und die Summationsformel aus?
In Pandas willst Du jetzt die selbe Filterung machen. Wie sieht da die Filterung aus?
Stimmen da die gefilterten Zahlen überein? Wie sieht die Summe ohne Filter aus?
Antworten