Wie erstelle ich eine Liste von Zufallszahlen ohne Duplikate?

110

Ich habe versucht, zu verwenden random.randint(0, 100), aber einige Zahlen waren die gleichen. Gibt es eine Methode / ein Modul zum Erstellen einer Liste eindeutiger Zufallszahlen?

Hinweis: Der folgende Code basiert auf einer Antwort und wurde hinzugefügt, nachdem die Antwort veröffentlicht wurde. Es ist kein Teil der Frage; Es ist die Lösung.

def getScores():
    # open files to read and write
    f1 = open("page.txt", "r");
    p1 = open("pgRes.txt", "a");

    gScores = [];
    bScores = [];
    yScores = [];

    # run 50 tests of 40 random queries to implement "bootstrapping" method 
    for i in range(50):
        # get 40 random queries from the 50
        lines = random.sample(f1.readlines(), 40);
iCodeLikeImDrunk
quelle
1
Wenn sie einzigartig sind, können sie im richtigen Kontext wirklich zufällig sein. Wie eine zufällige Stichprobe kann ersatzlose Indizes immer noch völlig zufällig sein.
Gbtimmon

Antworten:

179

Dies gibt eine Liste von 10 Zahlen zurück, die aus dem Bereich 0 bis 99 ohne Duplikate ausgewählt wurden.

import random
random.sample(range(100), 10)

In Bezug auf Ihr spezifisches Codebeispiel möchten Sie wahrscheinlich alle Zeilen aus der Datei einmal lesen und dann zufällige Zeilen aus der gespeicherten Liste im Speicher auswählen. Beispielsweise:

all_lines = f1.readlines()
for i in range(50):
    lines = random.sample(all_lines, 40)

Auf diese Weise müssen Sie vor Ihrer Schleife nur einmal aus der Datei lesen. Dies ist viel effizienter, als zum Anfang der Datei zurückzukehren und f1.readlines()bei jeder Schleifeniteration erneut aufzurufen .

Greg Hewgill
quelle
2
Diese Technik verschwendet Speicher, insbesondere bei großen Proben. Ich habe unten Code für eine viel speicher- und rechnerisch effizientere Lösung veröffentlicht, die einen linearen Kongruenzgenerator verwendet.
Thomas Lux
Ich wurde darauf hingewiesen, dass die LCG-Methode jedoch weniger "zufällig" ist. Wenn Sie also viele eindeutige Zufallssequenzen generieren möchten, ist die Vielfalt geringer als bei dieser Lösung. Wenn Sie nur eine Handvoll zufälliger Sequenzen benötigen, ist LCG der richtige Weg!
Thomas Lux
Danke Greg, es war nützlich
N Sivaram
15

Sie können die Verwendung Shuffle - Funktion aus dem Zufalls Modul wie folgt aus :

import random

my_list = list(xrange(1,100)) # list of integers from 1 to 99
                              # adjust this boundaries to fit your needs
random.shuffle(my_list)
print my_list # <- List of unique random numbers

Beachten Sie hier, dass die Shuffle-Methode keine erwartete Liste zurückgibt, sondern nur die als Referenz übergebene Liste mischt.

Ricardo Murillo
quelle
Es ist gut zu erwähnen, dass xrange nur in Python 2 und nicht in Python 3 funktioniert.
Shayan Shafiq
10

Sie können zunächst eine Liste von Zahlen von erstellen azu b, wo aund bsind jeweils die kleinsten und größten Zahlen in Ihrer Liste, mische es dann mit Fisher-Yates - Algorithmus oder der Python mit random.shuffleMethode.

ben
quelle
1
Das Generieren einer vollständigen Liste von Indizes ist eine Speicherverschwendung, insbesondere bei großen Stichproben. Ich habe unten Code für eine viel speicher- und rechnerisch effizientere Lösung veröffentlicht, die einen linearen Kongruenzgenerator verwendet.
Thomas Lux
8

Die in dieser Antwort vorgestellte Lösung funktioniert, kann jedoch mit dem Speicher problematisch werden, wenn die Stichprobengröße klein ist, die Population jedoch groß ist (zrandom.sample(insanelyLargeNumber, 10) . ).

Um das zu beheben, würde ich folgendes tun:

answer = set()
sampleSize = 10
answerSize = 0

while answerSize < sampleSize:
    r = random.randint(0,100)
    if r not in answer:
        answerSize += 1
        answer.add(r)

# answer now contains 10 unique, random integers from 0.. 100
inspectorG4dget
quelle
random.sampleVerwendet diesen Ansatz jetzt für eine kleine Anzahl von Stichproben aus einer großen Population, sodass dieses Problem mit dem Speicher nicht mehr wirklich besteht. Obwohl zu dem Zeitpunkt, als diese Antwort geschrieben wurde, die Implementierung von random.shufflemöglicherweise anders war.
kyrill
5

Linearer kongruenter Pseudozufallszahlengenerator

O (1) Speicher

O (k) Operationen

Dieses Problem kann mit einem einfachen linearen Kongruenzgenerator gelöst werden . Dies erfordert einen konstanten Speicheraufwand (8 Ganzzahlen) und höchstens 2 * (Sequenzlänge) Berechnungen.

Alle anderen Lösungen verbrauchen mehr Speicher und mehr Rechenleistung! Wenn Sie nur wenige zufällige Sequenzen benötigen, ist diese Methode erheblich günstiger. NWenn Sie für Größenbereiche in der Größenordnung von Neindeutigen kSequenzen oder mehr generieren möchten , empfehle ich die akzeptierte Lösung mit den integrierten Methoden, random.sample(range(N),k)da diese optimiert wurde in Python auf Geschwindigkeit wurde.

Code

# Return a randomized "range" using a Linear Congruential Generator
# to produce the number sequence. Parameters are the same as for 
# python builtin "range".
#   Memory  -- storage for 8 integers, regardless of parameters.
#   Compute -- at most 2*"maximum" steps required to generate sequence.
#
def random_range(start, stop=None, step=None):
    import random, math
    # Set a default values the same way "range" does.
    if (stop == None): start, stop = 0, start
    if (step == None): step = 1
    # Use a mapping to convert a standard range into the desired range.
    mapping = lambda i: (i*step) + start
    # Compute the number of numbers in this range.
    maximum = (stop - start) // step
    # Seed range with a random integer.
    value = random.randint(0,maximum)
    # 
    # Construct an offset, multiplier, and modulus for a linear
    # congruential generator. These generators are cyclic and
    # non-repeating when they maintain the properties:
    # 
    #   1) "modulus" and "offset" are relatively prime.
    #   2) ["multiplier" - 1] is divisible by all prime factors of "modulus".
    #   3) ["multiplier" - 1] is divisible by 4 if "modulus" is divisible by 4.
    # 
    offset = random.randint(0,maximum) * 2 + 1      # Pick a random odd-valued offset.
    multiplier = 4*(maximum//4) + 1                 # Pick a multiplier 1 greater than a multiple of 4.
    modulus = int(2**math.ceil(math.log2(maximum))) # Pick a modulus just big enough to generate all numbers (power of 2).
    # Track how many random numbers have been returned.
    found = 0
    while found < maximum:
        # If this is a valid value, yield it in generator fashion.
        if value < maximum:
            found += 1
            yield mapping(value)
        # Calculate the next value in the sequence.
        value = (value*multiplier + offset) % modulus

Verwendung

Die Verwendung dieser Funktion "random_range" ist die gleiche wie für jeden Generator (wie "range"). Ein Beispiel:

# Show off random range.
print()
for v in range(3,6):
    v = 2**v
    l = list(random_range(v))
    print("Need",v,"found",len(set(l)),"(min,max)",(min(l),max(l)))
    print("",l)
    print()

Probenergebnisse

Required 8 cycles to generate a sequence of 8 values.
Need 8 found 8 (min,max) (0, 7)
 [1, 0, 7, 6, 5, 4, 3, 2]

Required 16 cycles to generate a sequence of 9 values.
Need 9 found 9 (min,max) (0, 8)
 [3, 5, 8, 7, 2, 6, 0, 1, 4]

Required 16 cycles to generate a sequence of 16 values.
Need 16 found 16 (min,max) (0, 15)
 [5, 14, 11, 8, 3, 2, 13, 1, 0, 6, 9, 4, 7, 12, 10, 15]

Required 32 cycles to generate a sequence of 17 values.
Need 17 found 17 (min,max) (0, 16)
 [12, 6, 16, 15, 10, 3, 14, 5, 11, 13, 0, 1, 4, 8, 7, 2, ...]

Required 32 cycles to generate a sequence of 32 values.
Need 32 found 32 (min,max) (0, 31)
 [19, 15, 1, 6, 10, 7, 0, 28, 23, 24, 31, 17, 22, 20, 9, ...]

Required 64 cycles to generate a sequence of 33 values.
Need 33 found 33 (min,max) (0, 32)
 [11, 13, 0, 8, 2, 9, 27, 6, 29, 16, 15, 10, 3, 14, 5, 24, ...]
Thomas Lux
quelle
1
Das ist sehr cool! Aber ich bin mir sicher, dass es die Frage wirklich beantwortet; Angenommen, ich möchte 2 Werte von 0 bis 4 abtasten. Ohne meine eigenen zu generieren prime, gibt die Funktion nur 4 mögliche Antworten zurück, da dies valuedie einzige zufällig ausgewählte Sache mit 4 möglichen Werten ist, wenn wir mindestens (4 wählen 2) = benötigen 6, (unter Berücksichtigung einer nicht zufälligen Reihenfolge). random_range(2,4)gibt Werte {(1, 0), (3, 2), (2, 1), (0, 3)} zurück, aber niemals das Paar (3,1) (oder (1,3)). Erwarten Sie bei jedem Funktionsaufruf neue zufällig generierte große Primzahlen?
Wowserx
1
(Ich gehe auch davon aus, dass Sie erwarten, dass die Leute die Sequenz mischen, nachdem Ihre Funktion sie zurückgegeben hat, wenn sie eine zufällige Reihenfolge wünschen, da random_range(v)sie vstattdessen zu eindeutigen Sequenzen zurückkehren v!)
wowserx
Total wahr! Es ist schwer zu balancieren, ob ein ganzzahliger Überlauf vermieden oder genügend zufällige Sequenzen generiert werden sollen. Ich habe die Funktion aktualisiert, um etwas mehr Zufälligkeit zu integrieren, aber sie ist immer noch nicht so zufällig wie v!. Dies hängt davon ab, ob Sie die Funktion mehrmals verwenden möchten. Diese Lösung wird am besten verwendet, wenn Sie aus einem großen Wertebereich generieren (wenn der Speicherverbrauch anderer viel höher wäre). Ich werde mehr darüber nachdenken, danke!
Thomas Lux
4

Wenn die Liste von N Zahlen von 1 bis N zufällig generiert wird, besteht die Möglichkeit, dass einige Zahlen wiederholt werden.

Wenn Sie eine Liste von Zahlen von 1 bis N in zufälliger Reihenfolge wünschen, füllen Sie ein Array mit ganzen Zahlen von 1 bis N und verwenden Sie dann ein Fisher-Yates-Shuffle oder Pythons random.shuffle().

Mitch Wheat
quelle
3

Wenn Sie extrem große Zahlen abtasten müssen, können Sie diese nicht verwenden range

random.sample(range(10000000000000000000000000000000), 10)

weil es wirft:

OverflowError: Python int too large to convert to C ssize_t

Wenn random.sampledie Anzahl der gewünschten Artikel aufgrund des zu kleinen Bereichs nicht erreicht werden kann

 random.sample(range(2), 1000)

es wirft:

 ValueError: Sample larger than population

Diese Funktion löst beide Probleme:

import random

def random_sample(count, start, stop, step=1):
    def gen_random():
        while True:
            yield random.randrange(start, stop, step)

    def gen_n_unique(source, n):
        seen = set()
        seenadd = seen.add
        for i in (i for i in source() if i not in seen and not seenadd(i)):
            yield i
            if len(seen) == n:
                break

    return [i for i in gen_n_unique(gen_random,
                                    min(count, int(abs(stop - start) / abs(step))))]

Verwendung mit extrem großen Stückzahlen:

print('\n'.join(map(str, random_sample(10, 2, 10000000000000000000000000000000))))

Beispielergebnis:

7822019936001013053229712669368
6289033704329783896566642145909
2473484300603494430244265004275
5842266362922067540967510912174
6775107889200427514968714189847
9674137095837778645652621150351
9969632214348349234653730196586
1397846105816635294077965449171
3911263633583030536971422042360
9864578596169364050929858013943

Verwendung, wenn der Bereich kleiner als die Anzahl der angeforderten Artikel ist:

print(', '.join(map(str, random_sample(100000, 0, 3))))

Beispielergebnis:

2, 0, 1

Es funktioniert auch mit negativen Bereichen und Schritten:

print(', '.join(map(str, random_sample(10, 10, -10, -2))))
print(', '.join(map(str, random_sample(10, 5, -5, -2))))

Beispielergebnisse:

2, -8, 6, -2, -4, 0, 4, 10, -6, 8
-3, 1, 5, -1, 3
Handwerker
quelle
Was ist, wenn Sie über 8 Milliarden Zahlen generieren, die früher oder später zu groß werden
david_adler
Diese Antwort weist bei großen Stichproben einen schwerwiegenden Fehler auf. Die Kollisionswahrscheinlichkeit wächst linear mit jedem Schritt. Ich habe eine Lösung mit einem linearen Kongruenzgenerator veröffentlicht, der über O (1) Speicher-Overhead und O (k) -Schritte verfügt, die zum Generieren von k Zahlen erforderlich sind. Dies kann viel effizienter gelöst werden!
Thomas Lux
Diese Antwort ist definitiv besser, wenn Sie eine Anzahl von zufälligen Sequenzen in der Reihenfolge der Länge der Sequenz generieren möchten! Die LCG-Methode ist weniger "zufällig", wenn es darum geht, mehrere eindeutige Sequenzen zu erzeugen.
Thomas Lux
"Diese Funktion löst beide Probleme" Wie wird das zweite Problem behoben? Sie können immer noch nicht 1000 Proben aus einer Population von 2 nehmen. Anstatt eine Ausnahme auszulösen, erhalten Sie ein falsches Ergebnis. Das ist kaum eine Lösung des "Problems" (was zunächst wirklich kein Problem ist, da es überhaupt nicht sinnvoll ist, k eindeutige Stichproben von einer Population von n <k anzufordern ).
kyrill
1

Sie können Numpy verwenden Bibliothek für eine schnelle Antwort verwenden, wie unten gezeigt -

Das angegebene Code-Snippet listet 6 eindeutige Zahlen im Bereich von 0 bis 5 auf. Sie können die Parameter für Ihren Komfort anpassen.

import numpy as np
import random
a = np.linspace( 0, 5, 6 )
random.shuffle(a)
print(a)

Ausgabe

[ 2.  1.  5.  3.  4.  0.]

Es gibt keine Einschränkungen, wie wir in random.sample sehen, wie hier beschrieben .

Hoffe das hilft ein bisschen.

dataLeo
quelle
1

Die hier gegebene Antwort funktioniert sowohl in Bezug auf Zeit als auch auf Speicher sehr gut, ist jedoch etwas komplizierter, da fortgeschrittene Python-Konstrukte wie Yield verwendet werden. Die einfachere Antwort funktioniert in der Praxis gut, aber das Problem bei dieser Antwort ist, dass sie viele falsche Ganzzahlen erzeugen kann, bevor die erforderliche Menge tatsächlich erstellt wird. Probieren Sie es mit populationsSize = 1000, sampleSize = 999 aus. Theoretisch besteht die Möglichkeit, dass es nicht beendet wird.

Die folgende Antwort befasst sich mit beiden Fragen, da sie deterministisch und etwas effizient ist, derzeit jedoch nicht so effizient wie die beiden anderen.

def randomSample(populationSize, sampleSize):
  populationStr = str(populationSize)
  dTree, samples = {}, []
  for i in range(sampleSize):
    val, dTree = getElem(populationStr, dTree, '')
    samples.append(int(val))
  return samples, dTree

wo die Funktionen getElem, percolateUp sind wie unten definiert

import random

def getElem(populationStr, dTree, key):
  msd  = int(populationStr[0])
  if not key in dTree.keys():
    dTree[key] = range(msd + 1)
  idx = random.randint(0, len(dTree[key]) - 1)
  key = key +  str(dTree[key][idx])
  if len(populationStr) == 1:
    dTree[key[:-1]].pop(idx)
    return key, (percolateUp(dTree, key[:-1]))
  newPopulation = populationStr[1:]
  if int(key[-1]) != msd:
    newPopulation = str(10**(len(newPopulation)) - 1)
  return getElem(newPopulation, dTree, key)

def percolateUp(dTree, key):
  while (dTree[key] == []):
    dTree[key[:-1]].remove( int(key[-1]) )
    key = key[:-1]
  return dTree

Schließlich betrug das Timing im Durchschnitt etwa 15 ms für einen großen Wert von n, wie unten gezeigt.

In [3]: n = 10000000000000000000000000000000

In [4]: %time l,t = randomSample(n, 5)
Wall time: 15 ms

In [5]: l
Out[5]:
[10000000000000000000000000000000L,
 5731058186417515132221063394952L,
 85813091721736310254927217189L,
 6349042316505875821781301073204L,
 2356846126709988590164624736328L]
aak318
quelle
Sie denken, dass die Antwort kompliziert ist? Was ist das dann?! Und dann gibt es noch die andere Antwort , die viele "falsche ganze Zahlen" erzeugt. Ich habe Ihre Implementierung mit einer von Ihnen angegebenen Beispieleingabe ausgeführt (populationsgröße = 1000, sampleSize = 999). Ihre Version ruft die random.randintFunktion 3996 mal auf, während die andere cca. 6000 mal. Keine so große Verbesserung, oder?
kyrill
@kyrill, Ihre Meinung zu dieser Antwort
aak318
1

Um ein Programm zu erhalten, das eine Liste von Zufallswerten ohne Duplikate generiert, die deterministisch, effizient und mit grundlegenden Programmierkonstrukten erstellt ist, berücksichtigen Sie die extractSamplesunten definierte Funktion :

def extractSamples(populationSize, sampleSize, intervalLst) :
    import random
    if (sampleSize > populationSize) :
        raise ValueError("sampleSize = "+str(sampleSize) +" > populationSize (= " + str(populationSize) + ")")
    samples = []
    while (len(samples) < sampleSize) :
        i = random.randint(0, (len(intervalLst)-1))
        (a,b) = intervalLst[i]
        sample = random.randint(a,b)
        if (a==b) :
            intervalLst.pop(i)
        elif (a == sample) : # shorten beginning of interval                                                                                                                                           
            intervalLst[i] = (sample+1, b)
        elif ( sample == b) : # shorten interval end                                                                                                                                                   
            intervalLst[i] = (a, sample - 1)
        else :
            intervalLst[i] = (a, sample - 1)
            intervalLst.append((sample+1, b))
        samples.append(sample)
    return samples

Die Grundidee besteht darin, Intervalle intervalLstfür mögliche Werte zu verfolgen , aus denen unsere erforderlichen Elemente ausgewählt werden können. Dies ist insofern deterministisch, als wir garantiert eine Stichprobe innerhalb einer festgelegten Anzahl von Schritten erzeugen (ausschließlich abhängig von populationSizeundsampleSize ) .

Um die obige Funktion zum Generieren unserer erforderlichen Liste zu verwenden,

In [3]: populationSize, sampleSize = 10**17, 10**5

In [4]: %time lst1 = extractSamples(populationSize, sampleSize, [(0, populationSize-1)])
CPU times: user 289 ms, sys: 9.96 ms, total: 299 ms
Wall time: 293 ms

Wir können auch mit einer früheren Lösung vergleichen (für einen niedrigeren Wert von populationsgröße)

In [5]: populationSize, sampleSize = 10**8, 10**5

In [6]: %time lst = random.sample(range(populationSize), sampleSize)
CPU times: user 1.89 s, sys: 299 ms, total: 2.19 s
Wall time: 2.18 s

In [7]: %time lst1 = extractSamples(populationSize, sampleSize, [(0, populationSize-1)])
CPU times: user 449 ms, sys: 8.92 ms, total: 458 ms
Wall time: 442 ms

Beachten Sie, dass ich den populationSizeWert reduziert habe , da bei Verwendung der random.sampleLösung ein Speicherfehler für höhere Werte auftritt (auch in den vorherigen Antworten hier und hier erwähnt ). Bei den oben genannten Werten können wir auch beobachten, dass extractSamplesder random.sampleAnsatz übertroffen wird .

PS: Obwohl der Kernansatz meiner früheren Antwort ähnlich ist , gibt es wesentliche Änderungen in der Implementierung sowie im Ansatz sowie eine Verbesserung der Klarheit.

aak318
quelle
0

Eine sehr einfache Funktion, die auch Ihr Problem löst

from random import randint

data = []

def unique_rand(inicial, limit, total):

        data = []

        i = 0

        while i < total:
            number = randint(inicial, limit)
            if number not in data:
                data.append(number)
                i += 1

        return data


data = unique_rand(1, 60, 6)

print(data)


"""

prints something like 

[34, 45, 2, 36, 25, 32]

"""
Vinicius Turin
quelle
0

Das Problem bei den satzbasierten Ansätzen ("Wenn zufällige Werte in Rückgabewerten erneut versucht werden") besteht darin, dass ihre Laufzeit aufgrund von Kollisionen (die eine weitere Wiederholung "erneut versuchen" erfordern) unbestimmt ist, insbesondere wenn eine große Anzahl zufälliger Werte zurückgegeben wird aus dem Bereich.

Eine Alternative, die für diese nicht deterministische Laufzeit nicht anfällig ist, ist die folgende:

import bisect
import random

def fast_sample(low, high, num):
    """ Samples :param num: integer numbers in range of
        [:param low:, :param high:) without replacement
        by maintaining a list of ranges of values that
        are permitted.

        This list of ranges is used to map a random number
        of a contiguous a range (`r_n`) to a permissible
        number `r` (from `ranges`).
    """
    ranges = [high]
    high_ = high - 1
    while len(ranges) - 1 < num:
        # generate a random number from an ever decreasing
        # contiguous range (which we'll map to the true
        # random number).
        # consider an example with low=0, high=10,
        # part way through this loop with:
        #
        # ranges = [0, 2, 3, 7, 9, 10]
        #
        # r_n :-> r
        #   0 :-> 1
        #   1 :-> 4
        #   2 :-> 5
        #   3 :-> 6
        #   4 :-> 8
        r_n = random.randint(low, high_)
        range_index = bisect.bisect_left(ranges, r_n)
        r = r_n + range_index
        for i in xrange(range_index, len(ranges)):
            if ranges[i] <= r:
                # as many "gaps" we iterate over, as much
                # is the true random value (`r`) shifted.
                r = r_n + i + 1
            elif ranges[i] > r_n:
                break
        # mark `r` as another "gap" of the original
        # [low, high) range.
        ranges.insert(i, r)
        # Fewer values possible.
        high_ -= 1
    # `ranges` happens to contain the result.
    return ranges[:-1]
Orange
quelle
0
import random

sourcelist=[]
resultlist=[]

for x in range(100):
    sourcelist.append(x)

for y in sourcelist:
    resultlist.insert(random.randint(0,len(resultlist)),y)

print (resultlist)
user85510
quelle
1
Willkommen bei Stackoverflow. Bitte erläutern Sie Ihre Antwort, warum und wie das Problem dadurch gelöst wird, dass andere Ihre Antwort leicht verstehen können.
Oktobus
Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten. Aus der Überprüfung
doppelter Piepton
-1

Wenn Sie sicherstellen möchten, dass die hinzugefügten Zahlen eindeutig sind, können Sie ein Set-Objekt verwenden

Wenn Sie 2.7 oder höher verwenden, oder importieren Sie das Sets-Modul, wenn nicht.

Wie andere bereits erwähnt haben, bedeutet dies, dass die Zahlen nicht wirklich zufällig sind.

Recaiden
quelle
-1

Ganzzahlen ohne Ersatz zwischen minvalund abtasten maxval:

import numpy as np

minval, maxval, n_samples = -50, 50, 10
generator = np.random.default_rng(seed=0)
samples = generator.permutation(np.arange(minval, maxval))[:n_samples]

# or, if minval is 0,
samples = generator.permutation(maxval)[:n_samples]

mit jax:

import jax

minval, maxval, n_samples = -50, 50, 10
key = jax.random.PRNGKey(seed=0)
samples = jax.random.shuffle(key, jax.numpy.arange(minval, maxval))[:n_samples]
Grisaitis
quelle
Warum würden Sie eine Permutaiton einer möglicherweise großen Anzahl von Elementen erzeugen und dann nur das erste auswählen n_samples? Was ist Ihre Begründung für diesen Ansatz? Können Sie erklären, was die Vorteile Ihres Ansatzes im Vergleich zu einer der zahlreichen vorhandenen Antworten sind (die meisten davon vor 8 Jahren)?
Cyrill
Tatsächlich hat meine Antwort eine ähnliche Komplexität wie andere Antworten mit den höchsten Stimmen und ist schneller, weil sie Numpy verwendet. andere, am besten random.shufflegewählte Methoden , die Mersenne Twister verwenden, sind viel langsamer als die von numpy (und wahrscheinlich jax) angebotenen Algen. numpy und jax ermöglichen andere Algorithmen zur Erzeugung von Zufallszahlen. jax ermöglicht auch das Kompilieren und Differenzieren von jit, was für die stochastische Differenzierung nützlich sein kann. Auch in Bezug auf ein "möglicherweise großes" Array tun einige der am besten bewerteten Antworten genau dasselbe random.shuffle, was ich nicht für sündig oder sogar absolut sündig halte
Grisaitis
1
Ich bin mir nicht sicher, was Sie unter " random.shuffleverwendet Mersenne Twister" verstehen - es ist Fisher-Yates-Shuffle, wie in mehreren Antworten erwähnt. Es hat eine lineare Zeitkomplexität und kann daher möglicherweise nicht asymptotisch langsamer sein als Algorithmen, die von einer anderen Bibliothek angeboten werden, sei es numpy oder auf andere Weise. Wenn numpy schneller ist, liegt dies nur daran, dass es in C implementiert ist. Dies rechtfertigt jedoch nicht die Erzeugung einer großen Permutation (eine, die möglicherweise nicht einmal in den Speicher passt), sondern nur die Auswahl einiger Elemente. Außer Ihrer gibt es keine einzige Antwort, die dies tut.
kyrill
Ich entschuldige mich, ich habe gelesen, dass Python Random Mersenne Twister als Prng verwendet hat. Haben Sie eine Quelle, damit ich mehr über Fisher Yates und die Rolle in random.shuffle erfahren kann?
Grisaitis
Hier gibt es bereits zwei separate Links zu Wikipedia mit zwei separaten Antworten. Wenn Wikipedia für Sie nicht gut genug ist, finden Sie am Ende des Artikels 14 Referenzen. Und dann ist da noch Google. Hilft das? Oh, und das randomModul ist in Python geschrieben, so dass Sie seine Quelle leicht anzeigen können (versuchen random.__file__).
Cyrill
-3

Von der CLI in Win XP:

python -c "import random; print(sorted(set([random.randint(6,49) for i in range(7)]))[:6])"

In Kanada haben wir das 6/49 Lotto. Ich wickle einfach den obigen Code in lotto.bat ein und starte C:\home\lotto.batoder einfach C:\home\lotto.

Weil random.randintich oft eine Zahl wiederhole, benutze ich setmitrange(7) und kürze sie dann auf eine Länge von 6.

Wenn sich eine Zahl mehr als zweimal wiederholt, beträgt die resultierende Listenlänge gelegentlich weniger als 6.

EDIT: Ist jedoch random.sample(range(6,49),6)der richtige Weg.

exbctel
quelle
-3
import random
result=[]
for i in range(1,50):
    rng=random.randint(1,20)
    result.append(rng)
user2904400
quelle
1
Können Sie erklären, wie dies Duplikate vermeidet? Aus diesem Code-Dump ist dies nicht ersichtlich.
Toby Speight
Das tut es nicht. print len(result), len(set(result)). Sie würden erwarten, dass resultdies nur einmal bei jedem 1.0851831788708547256608362340568947172111832359638926... × 10^20Versuch eindeutige Elemente enthält .
Jedi