Ich versuche, ein zufallsbasiertes System zu implementieren, das durch vorherige Ereignisse verzerrt ist.
Hintergrund: Vor einigen Jahren erinnere ich mich an ein Update für World of Warcraft, in dem angekündigt wurde, einen neuen Chancenrechner zu implementieren, der stacheligen Ereignisketten entgegenwirkt. (zB kritische Treffer erzielen oder mehrmals hintereinander ausweichen). Die Idee war, dass für den Fall, dass Sie einem Treffer ausweichen würden, die Wahrscheinlichkeit, dass Sie dem nächsten Treffer ausweichen würden, geringer wäre, aber es würde in beide Richtungen funktionieren. Wenn Sie einem Treffer nicht ausweichen, steigt auch die Wahrscheinlichkeit, dem nächsten Treffer auszuweichen. Der Haupttrick dabei war, dass die Ausweichchance bei mehreren Versuchen immer noch dem Prozentsatz entspricht, den der Spieler in seiner Statistik angegeben hat.
Diese Art von System hat mich damals sehr fasziniert, und jetzt bin ich in der Situation, eine solche Lösung zu brauchen.
Hier sind meine Probleme:
- Ich vermute, dass ich Online-Ressourcen zur Implementierung eines solchen Systems finden könnte, aber mir fehlen möglicherweise nur die relevanten Schlagworte, um es zu finden.
- Auch ich brauche diesen Ansatz, um ein System anzupassen, das nicht binomial ist (dh zwei Ergebnisse), sondern stattdessen 4 sich gegenseitig ausschließende Ereignisse enthält.
Mein derzeitiger Ansatz ähnelt dem eines Gewinnspiel-Ticketsystems. Wenn ein Ereignis eintritt, ändere ich die Gewichte zugunsten aller anderen Ereignisse. Dies könnte funktionieren, wenn die vier Ereignisse gleich wahrscheinlich wären, aber in meinem Fall müssen sie viel häufiger auftreten. Da das vorherrschende Ereignis jedoch häufiger auftritt, werden die Gewichte des anderen um ein vielfaches höher als beabsichtigt verschoben, und ich kann die Zahlen für die Gewichtsverschiebungen nicht finden, die erforderlich sind, um die durchschnittliche Ticketanzahl um die Anfangswerte des Ereignisses zu halten gegeben.
Ein paar Richtungsweiser oder ein anschauliches Beispiel wären sehr willkommen.
Antworten:
Grundsätzlich benötigen Sie einen "semi-zufälligen" Ereignisgenerator, der Ereignisse mit den folgenden Eigenschaften generiert:
Die durchschnittliche Häufigkeit, mit der jedes Ereignis eintritt, ist im Voraus festgelegt.
Es ist weniger wahrscheinlich, dass dasselbe Ereignis zweimal hintereinander auftritt als zufällig.
Die Ereignisse sind nicht vollständig vorhersehbar.
Eine Möglichkeit, dies zu tun, besteht darin, zuerst einen nicht zufälligen Ereignisgenerator zu implementieren , der die Ziele 1 und 2 erfüllt, und dann eine gewisse Zufälligkeit hinzuzufügen, um Ziel 3 zu erfüllen.
Für den nicht zufälligen Ereignisgenerator können wir einen einfachen Dithering- Algorithmus verwenden. Insbesondere sei p 1 , p 2 , ..., p n die relative Wahrscheinlichkeit der Ereignisse 1 bis n , und sei s = p 1 + p 2 + ... + p n die Summe der Gewichte. Mit dem folgenden Algorithmus können wir dann eine nicht zufällige, maximal gleich verteilte Folge von Ereignissen erzeugen:
Zunächst sei e 1 = e 2 = ... = e n = 0.
Um ein Ereignis zu erzeugen, inkrementieren Sie jedes e i um p i und geben Sie das Ereignis k aus, für das e k am größten ist (brechen Sie die Bindungen nach Belieben).
Dekrementieren Sie e k um s und wiederholen Sie den Vorgang ab Schritt 2.
Beispielsweise erzeugt dieser Algorithmus bei drei Ereignissen A, B und C mit p A = 5, p B = 4 und p C = 1 so etwas wie die folgende Folge von Ausgaben:
Beachten Sie, dass diese Folge von 30 Ereignissen genau 15 As, 12 Bs und 3 Cs enthält. Es ist nicht ganz optimal verteilt - es gibt ein paar Vorkommen von zwei As in einer Reihe, die hätte vermieden werden können - aber es kommt näher.
Um dieser Sequenz eine Zufälligkeit hinzuzufügen, haben Sie mehrere (sich nicht unbedingt gegenseitig ausschließende) Optionen:
Sie können Philipps Rat befolgen und ein "Deck" mit N anstehenden Ereignissen für eine entsprechend große Anzahl von N verwalten . Jedes Mal, wenn Sie ein Ereignis erzeugen müssen, wählen Sie ein zufälliges Ereignis aus dem Deck aus und ersetzen es durch das nächste Ereignis, das vom obigen Dithering-Algorithmus ausgegeben wird.
Wendet man dies auf das obige Beispiel mit N = 3 an, so erhält man zB:
Während N = 10 das eher zufällig aussehende ergibt:
Beachten Sie, dass die häufigen Ereignisse A und B aufgrund des Mischens viel häufiger auftreten, während die seltenen C-Ereignisse immer noch relativ weit auseinander liegen.
Sie können dem Dithering-Algorithmus Zufälligkeiten hinzufügen. Anstatt in Schritt 2 e i um p i zu inkrementieren, könnten Sie es beispielsweise um p i × random (0, 2) inkrementieren , wobei random ( a , b ) eine gleichmäßig verteilte Zufallszahl zwischen a und b ist ; Dies würde eine Ausgabe wie die folgende ergeben:
oder Sie könnten e i um p i + zufällig erhöhen (- c , c ), was ergeben würde (für c = 0,1 × s ):
oder für c = 0,5 × s :
Beachten Sie, dass das additive Schema für die seltenen Ereignisse C einen viel stärkeren Randomisierungseffekt hat als für die häufigen Ereignisse A und B, verglichen mit dem multiplikativen. Dies könnte oder könnte nicht wünschenswert sein. Natürlich können Sie auch eine Kombination dieser Schemata oder eine andere Anpassung der Inkremente verwenden, sofern dabei die Eigenschaft erhalten bleibt, dass das durchschnittliche Inkrement von e i gleich p i ist .
Alternativ können Sie die Ausgabe des Dithering-Algorithmus stören, indem Sie manchmal das ausgewählte Ereignis k durch ein zufälliges Ereignis ersetzen (das gemäß den Rohgewichten p i ausgewählt wird ). Solange Sie in Schritt 3 dasselbe k wie in Schritt 2 verwenden, gleicht der Dithering-Vorgang zufällige Schwankungen aus.
Hier ein Beispiel für eine Ausgabe mit einer Wahrscheinlichkeit von 10%, dass jedes Ereignis nach dem Zufallsprinzip ausgewählt wird:
und hier ist ein Beispiel mit einer 50% igen Chance, dass jede Ausgabe zufällig ist:
Sie können auch erwägen, eine Mischung aus rein zufälligen und geditherten Ereignissen in einen Deck / Mixing-Pool einzuspeisen, wie oben beschrieben, oder den Dithering-Algorithmus durch zufällige Auswahl von k zu randomisieren, wie durch die e i gewichtet (wobei negative Gewichte als Null behandelt werden).
Ps. Hier sind einige völlig zufällige Ereignissequenzen mit den gleichen Durchschnittsraten zum Vergleich:
Tangens: Da in den Kommentaren einige Debatten darüber geführt wurden, ob es für deckbasierte Lösungen erforderlich ist, das Deck vor dem Nachfüllen entleeren zu lassen, habe ich mich für einen grafischen Vergleich mehrerer Strategien zum Befüllen von Decks entschieden:
Darstellung mehrerer Strategien zur Erzeugung von halbzufälligen Münzwürfen (mit einem durchschnittlichen Verhältnis von Kopf zu Zahl von 50:50). Die horizontale Achse ist die Anzahl der Kippbewegungen, die vertikale Achse ist der kumulative Abstand vom erwarteten Verhältnis, gemessen als (Kopf - Zahl) / 2 = Kopf - Kippbewegungen / 2.
Die roten und grünen Linien in der Grafik zeigen zum Vergleich zwei nicht deckbasierte Algorithmen:
Die anderen drei Linien (blau, lila und cyan) zeigen die Ergebnisse von drei deckbasierten Strategien, die jeweils mit einem Deck von 40 Karten implementiert wurden, das anfänglich mit 20 "Kopf" -Karten und 20 "Schwanz" -Karten gefüllt ist:
Natürlich ist die obige Handlung nur eine einzelne Realisierung eines zufälligen Prozesses, aber sie ist einigermaßen repräsentativ. Insbesondere können Sie sehen, dass alle deckbasierten Prozesse eine begrenzte Verzerrung aufweisen und ziemlich nahe an der roten (deterministischen) Linie bleiben, während die rein zufällige grüne Linie schließlich abweicht.
(Tatsächlich ist die Abweichung der blauen, violetten und cyanfarbenen Linien von Null streng durch die Deckgröße begrenzt: Die blaue Linie kann niemals mehr als 10 Schritte von Null entfernt sein, die violette Linie kann nur 15 Schritte von Null entfernt sein In der Praxis ist es natürlich äußerst unwahrscheinlich, dass eine der Linien tatsächlich ihre Grenze erreicht, da die Tendenz besteht, dass sie näher an Null zurückkehren, wenn sie zu weit wandern aus.)
Auf einen Blick gibt es keinen offensichtlichen Unterschied zwischen den verschiedenen deckbasierten Strategien (obwohl die blaue Linie im Durchschnitt etwas näher an der roten Linie und die Cyan-Linie etwas weiter entfernt bleibt), aber eine genauere Betrachtung der blauen Linie zeigt ein deutliches deterministisches Muster: Alle 40 Ziehungen (markiert durch die gepunkteten grauen vertikalen Linien) trifft die blaue Linie genau auf die rote Linie bei Null. Die violetten und cyanfarbenen Linien sind nicht so stark eingeschränkt und können an jedem Punkt von Null abweichen.
Bei allen deckbasierten Strategien ist das wichtige Merkmal, das die Variation begrenzt, die Tatsache, dass das Deck deterministisch aufgefüllt wird , während die Karten zufällig aus dem Deck gezogen werden . Wenn die Karten, die zum Nachfüllen des Decks verwendet wurden, selbst zufällig ausgewählt würden, würden alle deckbasierten Strategien nicht mehr von der reinen Zufallsauswahl (grüne Linie) zu unterscheiden sein.
quelle
Nicht würfeln, Karten austeilen.
Nehmen Sie alle möglichen Ergebnisse Ihres RNG, fügen Sie sie in eine Liste ein, mischen Sie sie nach dem Zufallsprinzip und geben Sie die Ergebnisse in der zufälligen Reihenfolge zurück. Wenn Sie am Ende der Liste angekommen sind, wiederholen Sie den Vorgang.
Die Ergebnisse werden immer noch gleichmäßig verteilt, aber die einzelnen Ergebnisse wiederholen sich erst, wenn das Letzte der Liste auch das Erste des nächsten ist.
Wenn dies für Ihren Geschmack etwas zu vorhersehbar ist, können Sie eine Liste verwenden, die
n
die Anzahl der möglichen Ergebnisse multipliziert und jedes mögliche Ergebnisn
vor dem Mischen einfügt. Sie können die Liste auch neu mischen, bevor sie vollständig iteriert wird.quelle
Sie könnten einen Markov-Zufallsgraphen ausprobieren . Betrachten Sie jedes Ereignis, das auftreten kann, als Knoten in einem Diagramm. Stellen Sie von jedem Ereignis aus einen Link zu jedem anderen Ereignis her, das möglicherweise danach kommen könnte. Jeder dieser Links wird mit der sogenannten Übergangswahrscheinlichkeit gewichtet . Anschließend führen Sie eine zufällige Wanderung des Diagramms gemäß dem Übergangsmodell durch.
Sie können beispielsweise eine Grafik erstellen, die das Ergebnis eines Angriffs darstellt (kritischer Treffer, Ausweichen usw.). Initialisiere den Startknoten so, dass er zufällig ausgewählt wird, abhängig von den Statistiken des Spielers. Überlegen Sie sich dann beim nächsten Angriff, was angesichts des Übergangsmodells als Nächstes passiert.
Es muss sorgfältig entschieden werden, wie die Übergänge gewichtet werden sollen. Zum einen müssen sich alle Übergänge, die von einem Knoten ausgehen, zu einer Wahrscheinlichkeit von 1 summieren. Eine einfache Sache, die Sie tun können, ist, einen Übergang von jedem Knoten zu jedem anderen Knoten mit einer Gewichtung durchzuführen, die der Wahrscheinlichkeit entspricht, dass diese Ereignisse auftreten a priori , da das aktuelle Ereignis nicht erneut eintreten kann.
Wenn Sie beispielsweise drei Ereignisse haben:
Sie können das Übergangsmodell so einrichten, dass ein kritischer Treffer nicht erneut auftritt, indem Sie einfach seine Wahrscheinlichkeitsmasse gleichmäßig auf die anderen Ereignisse verteilen:
BEARBEITEN: Wie die Kommentare unten sagen, ist dieses Modell nicht kompliziert genug, um das gewünschte Verhalten zu erzielen. Stattdessen müssen Sie möglicherweise mehrere zusätzliche Status hinzufügen!
quelle
Hier ist eine Implementierung, die ich in C # erstellt habe:
Ich habe ein paar Kommentare hinzugefügt, damit Sie sehen können, was ich tue.
Hoffe, das hilft, bitte schlagen Sie Verbesserungen an diesem Code in den Kommentaren vor, danke!
quelle
Lassen Sie mich die Antwort von mklingen etwas verallgemeinern . Grundsätzlich möchten Sie das Gambler's Fallacy implementieren , obwohl ich hier eine allgemeinere Methode bereitstellen werde:
Angenommen, es gibt
n
mögliche Ereignisse mit Wahrscheinlichkeitenp_1, p_2, ..., p_n
. Wenn ein Ereignisi
eingetreten ist, wird seine Wahrscheinlichkeit mit einem Faktor neu skaliert0≤a_i≤1/p_i
(letzterer ist wichtig, sonst haben Sie eine größere Wahrscheinlichkeit als eines und die anderen Ereignisse müssen negative Wahrscheinlichkeiten haben , was im Grunde genommen " Anti " -Ereignisse bedeutet. Oder so etwas) typischa_i<1
. Sie können beispielsweise wählena_i=p_i
, was bedeutet, dass die Wahrscheinlichkeit, dass ein Ereignis ein zweites Mal eintritt, die ursprüngliche Wahrscheinlichkeit ist, dass das Ereignis genau zweimal hintereinander eintritt. Beispielsweise hätte ein zweiter Münzwurf eine Wahrscheinlichkeit von 1/4 anstelle von 1/2. Auf der anderen Seite können Sie auch welche habena_i>1
, was bedeuten würde, einen "Glücksfall / Unglücksfall" auszulösen.Alle anderen Ereignisse sollen gleich wahrscheinlich relativ zueinander bleiben, dh sie müssen alle um den gleichen Faktor neu skaliert werden,
b_i
so dass die Summe aller Wahrscheinlichkeiten gleich eins ist, dhSo weit, so einfach. Fügen wir nun eine weitere Anforderung hinzu: Unter Berücksichtigung aller möglichen Sequenzen von zwei Ereignissen müssen die daraus extrahierten Einzelereigniswahrscheinlichkeiten die ursprünglichen Wahrscheinlichkeiten sein.
Lassen
bezeichnen die Wahrscheinlichkeit des Eintretens eines Ereignisses
j
nach dem Ereignisi
und beachten Sie, dass,p_ij≠p_ji
sofernb_i=b_j (2)
(was(1)
implizierta_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j
). Dies erfordert auch der Satz von Bayes, und dies impliziert auchwie gewünscht. Beachten Sie nur, wie dies bedeutet, dass man
a_i
alle anderen repariert.Nun wollen wir sehen, was passiert, wenn wir diese Prozedur mehrmals anwenden, dh für Sequenzen von drei und mehr Ereignissen. Grundsätzlich gibt es zwei Optionen für die Auswahl der manipulierten Wahrscheinlichkeiten des dritten Ereignisses:
a) Vergessen Sie das erste Ereignis und das Rig, als ob nur das zweite aufgetreten wäre, d. h
Beachten Sie, dass dies in der Regel gegen Bayes verstößt, da zB
p_jik≠p_ikj
in den meisten Fällen.b) Verwenden Sie die Wahrscheinlichkeiten
p_ij
(für festi
) als neue Wahrscheinlichkeiten,pi_j
aus denen Sie die neuen Wahrscheinlichkeitenpi_jk
fürk
das nächste Ereignis erhalten . Ob Sie die ändernai_j
oder nicht, liegt an Ihnen, aber beachten Sie, dass die neuenbi_j
aufgrund der geänderten definitiv anders sindpi_j
. Andererseits wird die Auswahlai_j
wahrscheinlich dadurch eingeschränkt, dass alle Permutationenijk
mit der gleichen Wahrscheinlichkeit auftreten müssen. Wir werden sehen...und deren zyklische Permutationen, die für die jeweiligen Fälle gleich sein müssen.
Ich fürchte, meine Fortsetzung muss noch eine Weile warten ...
quelle
Ich denke, die beste Option ist die zufällig gewichtete Artikelauswahl. Es gibt eine Implementierung für C # hier , aber sie können leicht gefunden oder auch für andere Sprachen erstellt werden.
Die Idee wäre, das Gewicht einer Option jedes Mal zu reduzieren, wenn sie ausgewählt wird, und es jedes Mal zu erhöhen, wenn sie nicht ausgewählt wird.
Wenn Sie beispielsweise das Gewicht der ausgewählten Option um verringern
NumOptions-1
und das Gewicht aller anderen Optionen um 1 erhöhen (wobei Sie darauf achten müssen, Elemente mit einem Gewicht von <0 zu entfernen und sie zu lesen, wenn sie über 0 steigen) , werden alle Optionen ungefähr ausgewählt über einen langen Zeitraum gleich oft, aber bei kürzlich ausgewählten Optionen ist die Wahrscheinlichkeit, dass sie ausgewählt werden, sehr viel geringer.Das Problem bei der Verwendung einer zufälligen Reihenfolge besteht darin, dass Sie nach Auswahl jeder Option mit 100% iger Sicherheit vorhersagen können, welche Option als Nächstes ausgewählt wird. Das ist nicht sehr zufällig.
quelle
Meine Antwort ist falsch, mein Test war fehlerhaft.
Ich lasse diese Antwort hier für die Diskussion und Kommentare, die auf die Fehler in diesem Design hinweisen, aber der eigentliche Test war falsch.
quelle
Sie könnten tun, was im Wesentlichen ein Filter ist. Verfolgen Sie die letzten n Ereignisse. Die Wahrscheinlichkeit ist ein Teil eines Filters, der auf diese Ereignisse angewendet wird. Der 0. Filter ist die Basiswahrscheinlichkeit. Wenn 0, sind Sie ausgewichen, wenn 1, haben Sie versagt. Angenommen, die Basis betrug 25%, und der Filter nimmt bei jeder Iteration um die Hälfte ab. Ihr Filter wäre dann:
Fühlen Sie sich frei, um fortzufahren, wenn Sie es wünschen. Die Gesamtwahrscheinlichkeit dieses Schemas ist geringfügig höher als die Basiswahrscheinlichkeit von 0,25. Tatsächlich ist die Wahrscheinlichkeit bei dem gleichen Schema (ich nenne x die reale Wahrscheinlichkeit, p ist die Wahrscheinlichkeitseingabe):
Wenn man nach x auflöst, findet man die Antwort
p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8)
oder für unseren gegebenen Fallx=0.38461538461
. Aber was Sie wirklich wollen, ist, p mit x zu finden. Das ist ein schwierigeres Problem. Wenn Sie einen unendlichen Filter angenommen haben, wird das Problem zux+x*p=2*p
oderp=x/(2-x)
. Wenn Sie also Ihren Filter vergrößern, können Sie nach einer Zahl p suchen, die im Durchschnitt dieselben Ergebnisse liefert, jedoch in Abhängigkeit davon, wie erfolgreich Sie in letzter Zeit waren.Grundsätzlich verwenden Sie die vorherigen Werte, um die Akzeptanzschwelle für diese Runde zu bestimmen, und nehmen einen zufälligen Wert. Produziere dann den nächsten Zufallswert unter Berücksichtigung des Filters.
quelle
Wie Sie sich selbst vorgeschlagen haben, besteht einer der Ansätze darin, einen gewichteten Zufall zu implementieren. Die Idee ist, einen Zufallszahlen- (oder Ergebnis-) Generator zu erstellen, in dem Gewichte und Ergebnisse geändert werden können.
Hier ist eine Implementierung davon in Java.
BEARBEITEN Wenn Sie die Gewichte automatisch anpassen möchten, erhöhen Sie beispielsweise die Wahrscheinlichkeit von A, wenn das Ergebnis B war. Sie können entweder
nextOutcome()
Methode, sodass das Gewicht entsprechend dem Ergebnis geändert wirdsetWeight()
, um das Gewicht entsprechend dem Ergebnis zu ändern.quelle