Kann ich in R garantieren, dass ich nicht dieselbe Permutation generiere, wenn ich set.seed () setze und dann die Beispielfunktion zum Randomisieren einer Liste verwende?
dh ...
set.seed(25)
limit <- 3
myindex <- seq(0,limit)
for (x in seq(1,factorial(limit))) {
permutations <- sample(myindex)
print(permutations)
}
Dies erzeugt
[1] 1 2 0 3
[1] 0 2 1 3
[1] 0 3 2 1
[1] 3 1 2 0
[1] 2 3 0 1
[1] 0 1 3 2
Werden alle gedruckten Permutationen eindeutige Permutationen sein? Oder gibt es aufgrund der Art und Weise, wie dies implementiert wird, eine Chance, dass ich einige Wiederholungen bekomme?
Ich möchte dies garantiert ohne Wiederholungen tun können. Wie würde ich das machen?
(Ich möchte auch vermeiden, eine Funktion wie permn () verwenden zu müssen, die eine sehr mechanistische Methode zum Generieren aller Permutationen hat - sie sieht nicht zufällig aus.)
Nebenbemerkung --- es sieht so aus, als ob dieses Problem O ((n!)!) Ist, wenn ich mich nicht irre.
r
sampling
combinatorics
resampling
Mittenchops
quelle
quelle
limit
12 überschritten wird, wird Ihnen wahrscheinlich der Arbeitsspeicher ausgehen, wenn R versucht, Speicherplatz für zuzuweisenseq(1,factorial(limit))
. (12! Benötigt ungefähr 2 GB, also 13! Benötigt ungefähr 25 GB, 14! Ungefähr 350 GB usw.)Antworten:
Die Frage hat viele gültige Interpretationen. Die Kommentare - insbesondere der, der angibt, dass Permutationen von 15 oder mehr Elementen erforderlich sind (15! = 1307674368000 wird groß) - legen nahe, dass eine relativ kleine , ersatzlose Zufallsstichprobe aller n gewünscht wird ! = n * (n-1) (n-2) ... * 2 * 1 Permutationen von 1: n. Wenn dies zutrifft, gibt es (etwas) effiziente Lösungen.
Die folgende Funktion
rperm
akzeptiert zwei Argumenten
(die Größe der zu untersuchenden Permutationen) undm
(die Anzahl der zu zeichnenden Permutationen der Größe n). Wenn sich m n nähert oder n! Überschreitet, dauert die Funktion lange und gibt viele NA-Werte zurück: Sie ist für die Verwendung vorgesehen, wenn n relativ groß ist (z. B. 8 oder mehr) und m viel kleiner als n! Ist. Es funktioniert, indem eine Zeichenfolgendarstellung der bisher gefundenen Permutationen zwischengespeichert und dann (zufällig) neue Permutationen generiert werden, bis eine neue gefunden wird. Es nutzt die assoziative Listenindizierungsfunktion von R, um die Liste der zuvor gefundenen Permutationen schnell zu durchsuchen.Die Art der
replicate
ist , die Permutationen als zurückzukehren Spaltenvektoren; zB gibt die folgenden ein Beispiel in der ursprünglichen Frage, umgesetzt :Die Timings eignen sich hervorragend für kleine bis mittlere Werte von m bis zu etwa 10.000, verschlechtern sich jedoch bei größeren Problemen. Zum Beispiel wurde eine Probe von m = 10.000 Permutationen von n = 1000 Elementen (eine Matrix von 10 Millionen Werten) in 10 Sekunden erhalten; Eine Stichprobe von m = 20.000 Permutationen von n = 20 Elementen benötigte 11 Sekunden, obwohl die Ausgabe (eine Matrix von 400.000 Einträgen) viel kleiner war. Die Berechnung der Stichprobe von m = 100.000 Permutationen von n = 20 Elementen wurde nach 260 Sekunden abgebrochen (ich hatte nicht die Geduld, auf die Fertigstellung zu warten). Dieses Skalierungsproblem scheint mit Skalierungsineffizienzen bei der assoziativen Adressierung von R in Zusammenhang zu stehen. Man kann es umgehen, indem man Samples in Gruppen von beispielsweise 1000 oder so generiert, diese Samples dann zu einem großen Sample kombiniert und Duplikate entfernt.
Bearbeiten
Wir können eine nahezu lineare asymptotische Leistung erzielen, indem wir den Cache in eine Hierarchie von zwei Caches aufteilen, so dass R niemals eine große Liste durchsuchen muss. Erstellen Sie konzeptionell (obwohl nicht wie implementiert) ein Array, das durch die ersten Elemente einer Permutation indiziert ist . Einträge in diesem Array sind Listen aller Permutationen, die diese ersten Elemente gemeinsam nutzen. Um zu überprüfen, ob eine Permutation gesehen wurde, verwenden Sie ihre ersten Elemente, um ihren Eintrag im Cache zu finden, und suchen Sie dann nach dieser Permutation in diesem Eintrag. Wir können wählen , um die erwarteten Größen aller Listen auszugleichen. Die tatsächliche Implementierung verwendet keink k k k k -fold Array, das in ausreichender Allgemeinheit schwer zu programmieren wäre, aber stattdessen eine andere Liste verwendet.
Hier sind einige verstrichene Zeiten in Sekunden für einen Bereich von Permutationsgrößen und die Anzahl der angeforderten unterschiedlichen Permutationen:
(Die anscheinend anomale Beschleunigung von Größe = 10 auf Größe = 15 ist darauf zurückzuführen, dass die erste Ebene des Caches für Größe = 15 größer ist, wodurch die durchschnittliche Anzahl von Einträgen in den Listen der zweiten Ebene verringert wird, wodurch die assoziative Suche von R beschleunigt wird Kosten im RAM, die Ausführung könnte durch Erhöhen der Cache-Größe
k.head
der oberen Ebene beschleunigt werden . Nur das Erhöhen um 1 (was die Größe der oberen Ebene mit 10 multipliziert) beschleunigte sich beispielsweiserperm(100000, size=10)
von 11,77 Sekunden auf 8,72 Sekunden. Erstellen der oberen Ebene Cache 10-mal größer, jedoch keine nennenswerte Verstärkung erzielt, Taktung bei 8,51 Sekunden.)Mit Ausnahme von 1.000.000 eindeutigen Permutationen von 10 Elementen (ein wesentlicher Teil aller 10! = Etwa 3,63 Millionen solcher Permutationen) wurden praktisch nie Kollisionen festgestellt. In diesem Ausnahmefall gab es 169.301 Kollisionen, aber keine vollständigen Fehler (tatsächlich wurden eine Million eindeutige Permutationen erhalten).
Beachten Sie, dass bei großen Permutationsgrößen (größer als 20 oder so) die Chance, zwei identische Permutationen selbst in einer Probe mit einer Größe von 1.000.000.000 zu erhalten, verschwindend gering ist. Somit ist diese Lösung hauptsächlich in Situationen anwendbar, in denen (a) eine große Anzahl eindeutiger Permutationen von (b) zwischen und oder so Elementen erzeugt werden sollen, aber dennoch (c) wesentlich weniger als allePermutationen sind erforderlich.n = 5 n = 15 n !
Arbeitscode folgt.
quelle
> rperm(6,3) $failures [1] 9 $sample [,1] [,2] [,3] [1,] 3 1 3 [2,] 2 2 1 [3,] 1 3 2 [4,] 1 2 2 [5,] 3 3 1 [6,] 2 1 3
Mit
unique
in der richtigen Weise sollte den Trick tun:quelle
I "gehen m zur Seite Schritt Ihre erste Frage ein wenig, und deuten darauf hin , dass , wenn Ihr mit relativ kurzen Vektoren zu tun haben , Sie einfach alle Permutationen erzeugen könnte
permn
und sie nach dem Zufall bestellen diejenigen mitsample
:quelle
permn(10)
oder was auch immer nur einmal durchführen.set.seed
Sie Informationen dazu, wie Sie den Status des RNG speichern und später wiederherstellen können.