Betrachten Sie die folgenden vier Prozentsätze, dargestellt als float
Zahlen:
13.626332%
47.989636%
9.596008%
28.788024%
-----------
100.000000%
Ich muss diese Prozentsätze als ganze Zahlen darstellen. Wenn ich einfach benutze Math.round()
, erhalte ich insgesamt 101%.
14 + 48 + 10 + 29 = 101
Wenn ich benutze parseInt()
, erhalte ich insgesamt 97%.
13 + 47 + 9 + 28 = 97
Was ist ein guter Algorithmus, um eine beliebige Anzahl von Prozentsätzen als ganze Zahlen darzustellen und dabei insgesamt 100% beizubehalten?
Bearbeiten : Nachdem Sie einige der Kommentare und Antworten gelesen haben, gibt es eindeutig viele Möglichkeiten, dies zu lösen.
Um den Zahlen treu zu bleiben, ist das "richtige" Ergebnis meines Erachtens dasjenige, das den Gesamtfehler minimiert, definiert durch die Menge an Fehlerrundungen im Verhältnis zum tatsächlichen Wert:
value rounded error decision
----------------------------------------------------
13.626332 14 2.7% round up (14)
47.989636 48 0.0% round up (48)
9.596008 10 4.0% don't round up (9)
28.788024 29 2.7% round up (29)
Bei Gleichstand (3.33, 3.33, 3.33) kann eine willkürliche Entscheidung getroffen werden (zB 3, 4, 3).
quelle
Antworten:
Da keine der Antworten hier es richtig zu lösen scheint, ist hier meine halbverschleierte Version mit Unterstrichen :
quelle
Es gibt viele Möglichkeiten, dies zu tun, vorausgesetzt, Sie sind nicht besorgt über das Vertrauen in die ursprünglichen Dezimaldaten.
Die erste und vielleicht beliebteste Methode wäre die größte Restmethode
Welches ist im Grunde:
In Ihrem Fall würde es so aussehen:
Wenn Sie die ganzzahligen Teile nehmen, erhalten Sie
Das ergibt 97, und Sie möchten drei weitere hinzufügen. Nun betrachten Sie die Dezimalstellen, die sind
und nehmen Sie die größten, bis die Summe 100 erreicht. Sie würden also erhalten:
Alternativ können Sie einfach eine Dezimalstelle anstelle von ganzzahligen Werten anzeigen. Die Zahlen wären also 48,3 und 23,9 usw. Dies würde die Varianz von 100 um ein Vielfaches verringern.
quelle
Wahrscheinlich ist der "beste" Weg, dies zu tun (zitiert, da "bester" ein subjektiver Begriff ist), eine laufende (nicht integrale) Zählung Ihrer Position zu führen und diesen Wert zu runden .
Verwenden Sie dies dann zusammen mit dem Verlauf, um herauszufinden, welcher Wert verwendet werden soll. Verwenden Sie beispielsweise die von Ihnen angegebenen Werte:
In jeder Phase runden Sie die Zahl selbst nicht. Stattdessen runden Sie die angesammelten Wert und berechnen die beste Ganzzahl, die diesen Wert aus der vorherigen Basislinie erreicht - diese Basislinie ist der kumulative Wert (gerundet) der vorherigen Zeile.
Dies funktioniert, weil Sie nicht in jeder Phase Informationen verlieren, sondern die Informationen intelligenter nutzen. Die 'richtigen' gerundeten Werte befinden sich in der letzten Spalte und Sie können sehen, dass sie sich zu 100 summieren.
Sie können den Unterschied zwischen diesem und dem blinden Runden jedes Werts im dritten Wert oben sehen. Während
9.596008
normalerweise auf10
aufgerundet71.211976
wird, rundet das akkumulierte korrekt auf ab71
- dies bedeutet, dass nur9
zum Hinzufügen zur vorherigen Grundlinie von benötigt wird62
.Dies funktioniert auch für "problematische" Sequenzen wie drei Grobwerte , von denen einer aufgerundet werden sollte:
1/3
quelle
26, 25, 26, 23
, der zweite1, 0, 1, 0, 1, 0, ...
.Das Ziel der Rundung ist es, die geringste Fehlermenge zu erzeugen. Wenn Sie einen einzelnen Wert runden, ist dieser Prozess einfach und unkompliziert, und die meisten Menschen verstehen ihn leicht. Wenn Sie mehrere Zahlen gleichzeitig runden, wird der Prozess schwieriger - Sie müssen definieren, wie die Fehler kombiniert werden sollen, dh was minimiert werden muss.
Die gut gewählte Antwort von Varun Vohra minimiert die Summe der absoluten Fehler und ist sehr einfach zu implementieren. Es gibt jedoch Randfälle, die nicht behandelt werden - was sollte das Ergebnis einer Rundung sein?
24.25, 23.25, 27.25, 25.25
? Eine davon muss aufgerundet statt abgerundet werden. Sie würden wahrscheinlich nur willkürlich den ersten oder letzten in der Liste auswählen.Vielleicht ist es besser, den relativen Fehler anstelle des absoluten zu verwenden Fehlers zu verwenden. Durch Runden von 23,25 auf 24 wird es um 3,2% geändert, während durch Runden von 27,25 auf 28 nur um 2,8% geändert wird. Jetzt gibt es einen klaren Gewinner.
Es ist möglich, dies noch weiter zu optimieren. Eine übliche Technik ist zu quadrieren jeden Fehler, so dass große Fehler zählen unverhältnismäßig mehr als kleine. Ich würde auch einen nichtlinearen Divisor verwenden, um den relativen Fehler zu erhalten - es scheint nicht richtig, dass ein Fehler bei 1% 99-mal wichtiger ist als ein Fehler bei 99%. Im folgenden Code habe ich die Quadratwurzel verwendet.
Der vollständige Algorithmus lautet wie folgt:
Sie können beispielsweise immer noch mehr als eine Kombination mit derselben Fehlersumme haben
33.3333333, 33.3333333, 33.3333333
. Dies ist unvermeidlich und das Ergebnis ist völlig willkürlich. Der Code, den ich unten gebe, rundet die Werte auf der linken Seite lieber auf.So sieht es in Python aus.
Wie Sie an diesem letzten Beispiel sehen können, kann dieser Algorithmus immer noch nicht intuitive Ergebnisse liefern. Obwohl 89.0 keinerlei Rundung benötigt, musste einer der Werte in dieser Liste aufgerundet werden. Der niedrigste relative Fehler ergibt sich aus der Aufrundung dieses großen Werts und nicht aus den viel kleineren Alternativen.
Diese Antwort befürwortete ursprünglich, jede mögliche Kombination von Aufrunden / Abrunden durchzugehen, aber wie in den Kommentaren ausgeführt, funktioniert eine einfachere Methode besser. Der Algorithmus und der Code spiegeln diese Vereinfachung wider.
quelle
if actual == 0: return 0
zuerror_gen
funktioniert also großartig.isclose
Methode am Anfang vonround_to_100
?Summieren Sie NICHT die gerundeten Zahlen. Sie werden ungenaue Ergebnisse haben. Die Summe könnte in Abhängigkeit von der Anzahl der Begriffe und der Verteilung der Bruchteile erheblich abweichen.
Zeigen Sie die gerundeten Zahlen an, aber summieren Sie die tatsächlichen Werte. Je nachdem, wie Sie die Zahlen präsentieren, variiert die tatsächliche Vorgehensweise. Auf diese Weise erhalten Sie
Wie auch immer Sie gehen, Sie werden Diskrepanzen haben. In Ihrem Beispiel gibt es keine Möglichkeit, Zahlen anzuzeigen, die sich zu 100 addieren, ohne einen Wert falsch zu "runden" (der geringste Fehler wäre die Änderung von 9,596 auf 9).
BEARBEITEN
Sie müssen zwischen folgenden Optionen wählen:
Meistens ist der Umgang mit Prozentsätzen Nr. 3 die beste Option, da es offensichtlicher ist, wenn die Gesamtsumme 101% beträgt, als wenn die einzelnen Elemente nicht 100 ergeben, und Sie die einzelnen Elemente genau halten. "Rundung" 9.596 auf 9 ist meiner Meinung nach ungenau.
Um dies zu erklären, füge ich manchmal eine Fußnote hinzu, die erklärt, dass die einzelnen Werte gerundet sind und möglicherweise nicht 100% betragen. Jeder, der die Rundung versteht, sollte diese Erklärung verstehen können.
quelle
Ich habe einen Rundungshelfer für die C # -Version geschrieben. Der Algorithmus entspricht der Antwort von Varun Vohra. Ich hoffe, er hilft.
Es besteht den folgenden Unit-Test:
quelle
Sie können versuchen, Ihren Fehler aufgrund von Rundungen zu verfolgen und dann gegen das Korn zu runden, wenn der akkumulierte Fehler größer als der Bruchteil der aktuellen Zahl ist.
Ich bin mir nicht sicher, ob dies im Allgemeinen funktionieren würde, aber es scheint ähnlich zu funktionieren, wenn die Reihenfolge umgekehrt ist:
Ich bin mir sicher, dass es Randfälle gibt, in denen dies möglicherweise nicht funktioniert, aber jeder Ansatz wird zumindest etwas willkürlich sein, da Sie Ihre Eingabedaten grundsätzlich ändern.
quelle
Ich habe einmal ein ungerundetes Werkzeug geschrieben, um die minimale Störung einer Reihe von Zahlen zu finden, die einem Ziel entsprechen. Es war ein anderes Problem, aber theoretisch könnte man hier eine ähnliche Idee verwenden. In diesem Fall haben wir eine Reihe von Möglichkeiten.
Für das erste Element können wir es also entweder auf 14 oder auf 13 abrunden. Die Kosten (im Sinne einer binären Ganzzahlprogrammierung) sind für die Aufrundung geringer als für die Abrundung, da die Abrundung dies erfordert Bewegen Sie diesen Wert um eine größere Strecke. Ebenso können wir jede Zahl auf- oder abrunden, sodass wir insgesamt 16 Auswahlmöglichkeiten haben.
Normalerweise würde ich das allgemeine Problem in MATLAB lösen, hier mit bintprog, einem Programmierwerkzeug für binäre Ganzzahlen, aber es müssen nur wenige Optionen getestet werden, sodass es mit einfachen Schleifen einfach genug ist, jede der 16 Alternativen zu testen. Angenommen, wir würden diesen Satz wie folgt abrunden:
Der gesamte absolute Fehler beträgt 1,25266. Sie kann durch folgende alternative Rundung leicht reduziert werden:
In der Tat wird dies die optimale Lösung in Bezug auf den absoluten Fehler sein. Wenn es 20 Begriffe gäbe, hätte der Suchraum natürlich die Größe 2 ^ 20 = 1048576. Für 30 oder 40 Begriffe hat dieser Raum eine signifikante Größe. In diesem Fall müssten Sie ein Tool verwenden, das den Raum effizient durchsuchen kann, möglicherweise mithilfe eines Verzweigungs- und gebundenen Schemas.
quelle
Ich denke, das Folgende wird das erreichen, wonach Sie suchen
Als letztes habe ich die Funktion mit den ursprünglich in der Frage angegebenen Zahlen ausgeführt, um sie mit der gewünschten Ausgabe zu vergleichen
Dies war anders als die Frage wollte => [48, 29, 14, 9]. Ich konnte das nicht verstehen, bis ich mir die gesamte Fehlerquote angesehen hatte
Im Wesentlichen führt das Ergebnis meiner Funktion tatsächlich die geringste Fehlermenge ein.
Geige hier
quelle
Ich bin mir nicht sicher, welche Genauigkeit Sie benötigen, aber ich würde einfach 1 die ersten
n
Zahlen addieren, wasn
die Obergrenze der Gesamtsumme der Dezimalstellen darstellt. In diesem Fall3
würde ich also 1 zu den ersten 3 Elementen hinzufügen und den Rest auf den Boden legen. Natürlich ist dies nicht sehr genau, einige Zahlen können aufgerundet oder abgerundet werden, wenn dies nicht der Fall sein sollte, aber es funktioniert in Ordnung und führt immer zu 100%.So
[ 13.626332, 47.989636, 9.596008, 28.788024 ]
wäre[14, 48, 10, 28]
dennMath.ceil(.626332+.989636+.596008+.788024) == 3
Sie können Benutzer jederzeit darüber informieren, dass die Zahlen gerundet sind und möglicherweise nicht sehr genau sind ...
quelle
Wenn Sie es runden, gibt es keine gute Möglichkeit, es in jedem Fall genau gleich zu bekommen.
Sie können den Dezimalteil der N Prozentsätze nehmen, die Sie haben (in dem Beispiel, das Sie angegeben haben, ist es 4).
Fügen Sie die Dezimalstellen hinzu. In Ihrem Beispiel haben Sie insgesamt Bruchteil = 3.
Decken Sie die 3 Zahlen mit den höchsten Anteilen ab und legen Sie den Rest auf den Boden.
(Entschuldigung für die Änderungen)
quelle
Wenn Sie sie wirklich abrunden müssen, gibt es hier bereits sehr gute Vorschläge (größter Rest, geringster relativer Fehler usw.).
Es gibt auch schon einen guten Grund, nicht zu runden (Sie erhalten mindestens eine Zahl, die "besser aussieht", aber "falsch" ist), und wie Sie das lösen können (warnen Sie Ihre Leser), und das ist, was ich tue.
Lassen Sie mich den "falschen" Nummernteil hinzufügen.
Angenommen, Sie haben drei Ereignisse / Entitäten / ... mit einigen Prozentsätzen, die Sie als ungefähr annähern:
Später ändern sich die Werte geringfügig auf
Die erste Tabelle hat das bereits erwähnte Problem, eine "falsche" Zahl zu haben: 33,34 ist näher an 33 als an 34.
Aber jetzt hast du einen größeren Fehler. Im Vergleich von Tag 2 mit Tag 1 stieg der reale Prozentwert für A um 0,01%, aber die Annäherung zeigt eine Abnahme um 1%.
Das ist ein qualitativer Fehler, wahrscheinlich schlimmer als der anfängliche quantitative Fehler.
Man könnte eine Annäherung für den gesamten Satz entwickeln, aber möglicherweise müssen Sie Daten am ersten Tag veröffentlichen, sodass Sie nichts über den zweiten Tag wissen. Wenn Sie sich also nicht wirklich annähern müssen, sollten Sie es wahrscheinlich besser nicht tun.
quelle
Überprüfen Sie, ob dies für meine Testfälle gültig ist oder nicht. Ich kann dies zum Laufen bringen.
Nehmen wir an, die Zahl ist k.
quelle
Ich habe die Methode aus Varun Vohras Antwort hier sowohl für Listen als auch für Diktate implementiert.
quelle
Hier ist eine einfachere Python-Implementierung der Antwort von @ varun-vohra:
Sie müssen
math
,itertools
,operator
.quelle
Für diejenigen, die die Prozentsätze in einer Pandas-Serie haben, ist hier meine Implementierung der Methode "Größter Rest" (wie in der Antwort von Varun Vohra ), bei der Sie sogar die Dezimalstellen auswählen können, auf die Sie runden möchten.
quelle
Dies ist ein Fall für die Rundung des Bankiers, auch bekannt als "Round Half-Even". Es wird von BigDecimal unterstützt. Damit soll sichergestellt werden, dass Rundungen ausgeglichen werden, dh weder die Bank noch der Kunde bevorzugt werden.
quelle