Dies ist eine Folgefrage zu einer Stackoverflow- Frage zum zufälligen Mischen eines Arrays .
Es gibt etablierte Algorithmen (wie das Knuth-Fisher-Yates-Shuffle ), mit denen man ein Array mischen sollte, anstatt sich auf "naive" Ad-hoc-Implementierungen zu verlassen.
Ich bin jetzt daran interessiert zu beweisen (oder zu widerlegen), dass mein naiver Algorithmus kaputt ist (wie in: Es werden nicht alle möglichen Permutationen mit gleicher Wahrscheinlichkeit erzeugt).
Hier ist der Algorithmus:
Wiederholen Sie die Schleife ein paar Mal (die Länge des Arrays sollte ausreichen), und erhalten Sie in jeder Iteration zwei zufällige Array-Indizes, und tauschen Sie die beiden Elemente dort aus.
Offensichtlich braucht dies mehr Zufallszahlen als KFY (doppelt so viel), aber abgesehen davon funktioniert es richtig? Und welche Anzahl von Iterationen ist angemessen (ist die "Länge des Arrays" ausreichend)?
quelle
Antworten:
Es ist kaputt, obwohl es eine ausgezeichnete Annäherung sein kann, wenn Sie genug mischen (wie die vorherigen Antworten gezeigt haben).
Überlegen Sie, wie oft Ihr Algorithmus Shuffles eines Element-Arrays generiert, in dem das erste Element festgelegt ist, . Wenn Permutationen mit gleicher Wahrscheinlichkeit generiert werden, sollte dies der Zeit passieren . Sei die relative Häufigkeit dieses Auftretens, nachdem mit Ihrem Algorithmus gemischt wurde. Lassen Sie uns auch großzügig sein und annehmen, Sie wählen tatsächlich unterschiedliche Paare von Indizes für Ihre Mischen gleichmäßig zufällig aus, so dass jedes Paar mit der Wahrscheinlichkeit =k ≥ 2 1 / k p n n 1 / ( kk k≥2 1/k pn n 2/(k(k-1))1/(k2) 2/(k(k−1)) . (Dies bedeutet, dass keine "trivialen" Shuffles verschwendet werden. Andererseits wird Ihr Algorithmus für ein Array mit zwei Elementen völlig zerstört, da Sie abwechselnd die beiden Elemente fixieren und austauschen, wenn Sie also nach einer vorgegebenen Anzahl von anhalten Schritte, es gibt überhaupt keine Zufälligkeit für das Ergebnis!)
Diese Frequenz erfüllt eine einfache Wiederholung, da das erste Element an seiner ursprünglichen Stelle gefunden wird, nachdem auf zwei getrennte Arten gemischt wurde. Einer ist, dass es nach Shuffles behoben wurde und das nächste Shuffle das erste Element nicht bewegt. Das andere ist, dass es nach Mischen verschoben wurde, aber das Mischen es zurück verschiebt. Die Chance , dass nicht das erste Element zu bewegen ist gleich = , während die Möglichkeit des ersten Elements zurück zu bewegen ist gleich = . Woher:n n n + 1 s t ( k - 1n+1 n n n+1st (k-2)/k1/ ( k(k−12)/(k2) (k−2)/k 2/(k(k-1))1/(k2) 2/(k(k−1))
Die Lösung ist
Wenn wir subtrahieren , sehen wir, dass die Frequenz um falsch ist . Für großes und ist eine gute Näherung . Dies zeigt, dass der Fehler in dieser bestimmten Frequenz mit der Anzahl der Auslagerungen im Verhältnis zur Größe des Arrays ( ) exponentiell abnimmt , was darauf hinweist, dass es bei großen Arrays schwierig ist, zu erkennen, ob Sie eine relativ große Anzahl von Auslagerungen vorgenommen haben - aber der Fehler ist immer da.( k - 31/k knk-1(k−3k−1)nk−1k k n n/kk−1kexp(−2nk−1) n/k
Eine umfassende Analyse der Fehler in allen Frequenzen ist schwierig. Es ist jedoch wahrscheinlich, dass sie sich wie folgt verhalten werden, was zeigt, dass Sie mindestens (die Anzahl der Auslagerungen) benötigen , um den Fehler akzeptabel klein zu machen. Eine ungefähre Lösung istn
Dabei sollte im Vergleich zu sehr klein sein . Dies impliziert, dass sogar für grobe Näherungen ein Mehrfaches von sollte ( dh , wenn in der Größenordnung von mal oder so liegt).1 / k n k ≤ 0,01 1 / kϵ 1/k n k ϵ 0.01 1/k
All dies wirft die Frage auf: Warum sollten Sie sich für einen Algorithmus entscheiden, der nicht ganz (aber nur annähernd) korrekt ist, genau die gleichen Techniken anwendet wie ein anderer Algorithmus, der nachweislich korrekt ist und dennoch mehr Berechnung erfordert?
Bearbeiten
Thilos Kommentar ist zutreffend (und ich hatte gehofft, dass niemand darauf hinweisen würde, sodass mir diese zusätzliche Arbeit erspart bleiben könnte!). Lassen Sie mich die Logik erklären.
Wenn Sie sicherstellen, dass Sie jedes Mal echte Swaps generieren, sind Sie total durchgeknallt. Das Problem, auf das ich für den Fall hingewiesen habe, erstreckt sich auf alle Arrays. Nur die Hälfte aller möglichen Permutationen kann durch Anwenden einer geraden Anzahl von Swaps erhalten werden. Die andere Hälfte ergibt sich aus einer ungeraden Anzahl von Swaps. In dieser Situation können Sie also niemals annähernd eine gleichmäßige Verteilung der Permutationen erzeugen (es gibt jedoch so viele mögliche, dass eine Simulationsstudie für ein beliebiges das Problem nicht erkennen kann). Das ist wirklich schlimm.kk = 2 k
Daher ist es ratsam, zufällige Swaps zu generieren, indem die beiden Positionen unabhängig voneinander zufällig generiert werden. Dies bedeutet, dass jedes Mal eine Chance besteht, ein Element mit sich selbst zu tauschen. das heißt, nichts zu tun. Dieser Prozess verlangsamt den Algorithmus ein wenig: Nach Schritten erwarten wir, dass nur etwa echte Swaps stattgefunden haben.n k - 11 / k n k - 1kN< N
Beachten Sie, dass die Größe des Fehlers mit der Anzahl der unterschiedlichen Auslagerungen monoton abnimmt. Das Durchführen von durchschnittlich weniger Swaps erhöht daher auch den Fehler im Durchschnitt. Dies ist jedoch ein Preis, den Sie bereit sein sollten zu zahlen, um das im ersten Punkt beschriebene Problem zu lösen. Folglich ist meine Fehlerschätzung konservativ niedrig, ungefähr um einen Faktor von .( k - 1 ) / k
Ich wollte auch auf eine interessante offensichtliche Ausnahme hinweisen: Ein genauer Blick auf die Fehlerformel deutet darauf hin, dass im Fall kein Fehler vorliegt . Dies ist kein Fehler: Es ist richtig. Ich habe hier jedoch nur eine Statistik untersucht, die sich auf die gleichmäßige Verteilung von Permutationen bezieht. Die Tatsache, dass der Algorithmus diese eine Statistik reproduzieren kann, wenn (nämlich die richtige Häufigkeit von Permutationen zu erhalten, die eine gegebene Position fixieren), garantiert nicht, dass die Permutationen tatsächlich gleichmäßig verteilt worden sind. Tatsächlich sind nach tatsächlichen Swaps die einzigen möglichen Permutationen, die erzeugt werden können, ,k=3 k=3 2n (123) (321) und die Identität. Nur letzteres legt eine bestimmte Position fest, so dass tatsächlich genau ein Drittel der Permutationen eine Position festlegt. Aber die Hälfte der Permutationen fehlt! Im anderen Fall sind nach tatsächlichen Swaps die einzig möglichen Permutationen , und . Wiederum wird genau eine von diesen jede gegebene Position fixieren, so dass wir wieder die korrekte Häufigkeit von Permutationen erhalten, die diese Position fixieren, aber wieder erhalten wir nur die Hälfte der möglichen Permutationen.2n+1 (12) (23) (13)
Dieses kleine Beispiel verdeutlicht die Hauptaspekte des Arguments: Indem wir "großzügig" sind, unterschätzen wir konservativ die Fehlerrate für eine bestimmte Statistik. Da diese Fehlerrate für alle ungleich Null ist , stellen wir fest, dass der Algorithmus fehlerhaft ist. Indem wir den Abfall der Fehlerrate für diese Statistik analysieren, bestimmen wir außerdem eine Untergrenze für die Anzahl der Iterationen des Algorithmus, die erforderlich sind, um überhaupt Hoffnung auf eine Annäherung an eine gleichmäßige Verteilung der Permutationen zu haben.k≥4
quelle
Ich denke, Ihr einfacher Algorithmus wird die Karten korrekt mischen, da die Anzahl der Mischen gegen unendlich geht.
Angenommen, Sie haben drei Karten: {A, B, C}. Angenommen, Ihre Karten beginnen in der folgenden Reihenfolge: A, B, C. Nach einem Shuffle haben Sie folgende Kombinationen:
Daher ist die Wahrscheinlichkeit, dass sich Karte A in Position {1,2,3} befindet, {5/9, 2/9, 2/9}.
Wenn wir die Karten ein zweites Mal mischen, dann:
Dies ergibt 0,407.
Mit der gleichen Idee können wir eine wiederkehrende Beziehung bilden, dh:
Codiert man dies in R (siehe Code unten), ergibt sich die Wahrscheinlichkeit, dass sich Karte A nach zehn Mischvorgängen an Position {1,2,3} mit {0,33334, 0,33333, 0,33333} befindet.
R-Code
quelle
Eine Möglichkeit, um zu sehen, dass Sie keine perfekt gleichmäßige Verteilung erhalten, ist die Teilbarkeit. In der Gleichverteilung beträgt die Wahrscheinlichkeit jeder Permutation . Wenn Sie eine Folge von t zufälligen Transpositionen erzeugen und dann Folgen nach ihrem Produkt sammeln, haben die Wahrscheinlichkeiten für eine ganze Zahl A die Form A / n 2 t . Wenn 1 / n ! = A / n 2 t , dann n 2 t / n ! = A1/n! t A/n2t A 1/n!=A/n2t n2t/n!=A . Nach Bertrands Postulat (ein Theorem) gibt es für Primzahlen, die im Nenner vorkommen und die n nicht teilen , also n 2 t / n ! ist keine ganze Zahl und es gibt keine Möglichkeit, die Transpositionen gleichmäßig in n zu unterteilen ! Permutationen. Wenn beispielsweise n = 52 , dann ist der Nenner von 1 / 52 ! teilbar ist durch 3 , 5 , 7 , . . . , 47 während der Nenner von 1 /n≥3 n n2t/n! n! n=52 1/52! 3,5,7,...,47 ist nicht, also A / 52 2 t nicht reduzieren 1 / 52 ! .1/522t A/522t 1/52!
Wie viele benötigen Sie, um eine zufällige Permutation gut zu approximieren? Die Erzeugung einer zufälligen Permutation durch zufällige Transpositionen wurde von Diaconis und Shahshahani unter Verwendung der Darstellungstheorie der symmetrischen Gruppe in analysiert
Diaconis, P., Shahshahani, M. (1981): "Erzeugen einer zufälligen Permutation mit zufälligen Transpositionen." Z. Wahrsch. Verw. Geb. 57, 159–179.
Eine Schlussfolgerung war, dass es 1 dauertTranspositionen in dem Sinne, dass nach(1-ϵ)112nlogn (1−ϵ)12nlogn (1+ϵ)12nlogn L2 7
quelle
Denken Sie daran, ich bin kein Statistiker, aber ich werde meine 2 Cent setzen.
Ich habe einen kleinen Test in R gemacht (Vorsicht, es ist sehr langsam für hoch
numTrials
, der Code kann wahrscheinlich optimiert werden):Dadurch wird eine Matrix
swaps
mitnumTrials+1
Zeilen (eine pro Versuch + Original) undnumElements
Spalten (eine pro Vektorelement) erstellt. Wenn die Methode korrekt ist, sollte sich die Verteilung jeder Spalte (dh der Werte für jedes Element über die Versuche) nicht von der Verteilung der Originaldaten unterscheiden.Da unsere ursprünglichen Daten normal verteilt waren, würden wir erwarten, dass alle Spalten nicht davon abweichen.
Wenn wir rennen
Wir bekommen:
das sieht sehr vielversprechend aus. Wenn wir nun statistisch bestätigen wollen, dass die Verteilungen nicht vom Original abweichen, könnten wir, glaube ich, einen Kolmogorov-Smirnov-Test verwenden (kann ein Statistiker dies bestätigen?) Und dies zum Beispiel tun
Das gibt uns p = 0,9926
Wenn wir alle Spalten überprüfen:
Und wir rennen
wir bekommen:
Für die große Mehrheit der Elemente des Arrays hat Ihre Swap-Methode also ein gutes Ergebnis geliefert, wie Sie auch sehen können, wenn Sie die Quartile betrachten.
Beachten Sie, dass die Situation bei einer geringeren Anzahl von Versuchen offensichtlich nicht so gut ist:
50 Versuche
100 Versuche
500 Versuche
quelle
So interpretiere ich Ihren Algorithmus in Pseudocode:
quelle