Làm cách nào để tạo danh sách các số ngẫu nhiên không trùng lặp?


110

Tôi đã thử sử dụng random.randint(0, 100), nhưng một số con số giống nhau. Có phương pháp / mô-đun nào để tạo danh sách các số ngẫu nhiên duy nhất không?

Lưu ý: Đoạn mã sau dựa trên một câu trả lời và đã được thêm vào sau khi câu trả lời được đăng. Nó không phải là một phần của câu hỏi; nó là giải pháp.

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);

1
Nếu chúng là duy nhất, chúng có thể thực sự ngẫu nhiên trong bối cảnh phù hợp. Giống như một mẫu chỉ mục ngẫu nhiên mà không cần thay thế vẫn có thể hoàn toàn ngẫu nhiên.
gbtimmon 24/09/2016

Câu trả lời:


180

Thao tác này sẽ trả về danh sách 10 số được chọn từ phạm vi 0 đến 99, không trùng lặp.

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

Với tham chiếu đến ví dụ mã cụ thể của bạn, bạn có thể muốn đọc tất cả các dòng từ tệp một lần và sau đó chọn các dòng ngẫu nhiên từ danh sách đã lưu trong bộ nhớ. Ví dụ:

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

Bằng cách này, bạn chỉ cần thực sự đọc từ tệp một lần trước vòng lặp của bạn. Thực hiện điều này hiệu quả hơn nhiều so với việc quay lại đầu tệp và gọi f1.readlines()lại cho mỗi lần lặp vòng lặp.


2
Kỹ thuật này gây lãng phí bộ nhớ, đặc biệt là đối với các mẫu lớn. Tôi đã đăng mã để có nhiều bộ nhớ hơn và tính toán giải pháp hiệu quả bên dưới sử dụng Bộ tạo thông số tuyến tính.
Thomas Lux,

Tôi chỉ ra rằng phương pháp LCG ít "ngẫu nhiên" hơn, vì vậy nếu bạn muốn tạo ra nhiều chuỗi ngẫu nhiên duy nhất, thì sự đa dạng sẽ ít hơn so với giải pháp này. Nếu bạn chỉ cần một số chuỗi ngẫu nhiên, LCG là một lựa chọn phù hợp!
Thomas Lux,

Cảm ơn Greg, Nó rất hữu ích
N Sivaram

15

Bạn có thể sử dụng chức năng xáo trộn từ mô-đun ngẫu nhiên như sau:

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

Lưu ý ở đây rằng phương thức xáo trộn không trả về bất kỳ danh sách nào như người ta có thể mong đợi, nó chỉ xáo trộn danh sách được chuyển bằng tham chiếu.


Thật tốt khi đề cập ở đây rằng xrange chỉ hoạt động trong Python 2 chứ không phải trong Python 3.
Shayan Shafiq

10

Trước tiên, bạn có thể tạo một danh sách các số từ ađến b, trong đó ablần lượt là các số nhỏ nhất và lớn nhất trong danh sách của mình, sau đó xáo trộn nó bằng thuật toán Fisher-Yates hoặc sử dụng random.shufflephương pháp của Python .


1
Tạo một danh sách đầy đủ các chỉ số là một sự lãng phí bộ nhớ, đặc biệt là đối với các mẫu lớn. Tôi đã đăng mã để có nhiều bộ nhớ hơn và tính toán giải pháp hiệu quả bên dưới sử dụng Bộ tạo thông số tuyến tính.
Thomas Lux,

8

Giải pháp được trình bày trong câu trả lời này hoạt động, nhưng nó có thể trở nên có vấn đề với bộ nhớ nếu kích thước mẫu nhỏ, nhưng dân số lại lớn (ví dụ random.sample(insanelyLargeNumber, 10)).

Để khắc phục điều đó, tôi sẽ làm như sau:

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

Bây giờ random.samplesử dụng cách tiếp cận này cho một số lượng nhỏ mẫu từ một quần thể lớn, vì vậy vấn đề này với bộ nhớ không thực sự tồn tại nữa. Mặc dù, tại thời điểm câu trả lời này được viết, việc thực hiện random.shufflecó thể đã khác.
kyrill

5

Bộ tạo số giả ngẫu nhiên tuyến tính công suất

O (1) Bộ nhớ

O (k) Hoạt động

Vấn đề này có thể được giải quyết bằng một Trình tạo thông số tuyến tính đơn giản . Điều này yêu cầu chi phí bộ nhớ không đổi (8 số nguyên) và tối đa là 2 * (độ dài chuỗi).

Tất cả các giải pháp khác sử dụng nhiều bộ nhớ hơn và nhiều máy tính hơn! Nếu bạn chỉ cần một vài chuỗi ngẫu nhiên, phương pháp này sẽ rẻ hơn đáng kể. Đối với phạm vi kích thước N, nếu bạn muốn tạo theo thứ tự chuỗi- Nduy nhất ktrở lên, tôi khuyên bạn nên sử dụng giải pháp được chấp nhận bằng cách sử dụng các phương pháp nội trang random.sample(range(N),k)vì điều này đã được tối ưu hóa trong python cho tốc độ.

# 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

Sử dụng

Việc sử dụng hàm này "random_range" giống như đối với bất kỳ trình tạo nào (như "range"). Một ví dụ:

# 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()

Kết quả mẫu

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, ...]

1
Điều này rất tuyệt! Nhưng tôi chắc chắn rằng nó thực sự trả lời câu hỏi; nói rằng tôi muốn lấy mẫu 2 giá trị từ 0 đến 4. Nếu không tạo của riêng tôi prime, hàm sẽ chỉ trả lại cho tôi 4 câu trả lời có thể có, vì valuelà thứ duy nhất được chọn ngẫu nhiên với 4 giá trị có thể, khi chúng ta cần ít nhất (4 chọn 2) = 6, (cho phép đặt hàng không ngẫu nhiên). random_range(2,4)sẽ trả về các giá trị {(1, 0), (3, 2), (2, 1), (0, 3)}, nhưng không bao giờ là cặp (3,1) (hoặc (1,3)). Bạn có mong đợi các số nguyên tố lớn mới được tạo ngẫu nhiên mỗi lần gọi hàm không?
wowserx

1
(Ngoài ra tôi đang giả định rằng bạn mong đợi người để shuffle chuỗi sau khi trở về chức năng của nó nếu họ muốn đặt hàng ngẫu nhiên, vì random_range(v)lợi nhuận lên đến vchuỗi duy nhất thay vì v!)
wowserx

Hoàn toàn đúng! Thật khó để cân bằng giữa việc tránh tràn số nguyên và tạo đủ chuỗi ngẫu nhiên. Tôi đã cập nhật chức năng để kết hợp thêm một chút ngẫu nhiên, nhưng nó vẫn không ngẫu nhiên như v !. Nó phụ thuộc vào việc bạn có muốn sử dụng hàm nhiều lần hay không. Giải pháp này được sử dụng tốt nhất khi bạn đang tạo từ một phạm vi giá trị lớn (khi mức tiêu thụ bộ nhớ của những người khác sẽ cao hơn nhiều). Tôi sẽ suy nghĩ về nó nhiều hơn, cảm ơn!
Thomas Lux,

4

Nếu danh sách N số từ 1 đến N được tạo ngẫu nhiên, thì có, có khả năng một số số có thể lặp lại.

Nếu bạn muốn danh sách các số từ 1 đến N theo thứ tự ngẫu nhiên, hãy điền vào một mảng với các số nguyên từ 1 đến N, sau đó sử dụng xáo trộn Fisher-Yates hoặc Python random.shuffle().


3

Nếu bạn cần lấy mẫu số lượng cực lớn, bạn không thể sử dụng range

random.sample(range(10000000000000000000000000000000), 10)

bởi vì nó ném:

OverflowError: Python int too large to convert to C ssize_t

Còn nếu random.sample không thể sản xuất số lượng mặt hàng bạn muốn do phạm vi quá nhỏ

 random.sample(range(2), 1000)

nó ném:

 ValueError: Sample larger than population

Chức năng này giải quyết cả hai vấn đề:

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))))]

Sử dụng với số lượng cực lớn:

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

Kết quả mẫu:

7822019936001013053229712669368
6289033704329783896566642145909
2473484300603494430244265004275
5842266362922067540967510912174
6775107889200427514968714189847
9674137095837778645652621150351
9969632214348349234653730196586
1397846105816635294077965449171
3911263633583030536971422042360
9864578596169364050929858013943

Cách sử dụng trong đó phạm vi nhỏ hơn số lượng mục được yêu cầu:

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

Kết quả mẫu:

2, 0, 1

Nó cũng hoạt động với các bước và phạm vi phủ định:

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

Kết quả mẫu:

2, -8, 6, -2, -4, 0, 4, 10, -6, 8
-3, 1, 5, -1, 3

gì xảy ra nếu bạn đang tạo ra hơn 8 tỷ số, sớm hay muộn sẽ nhìn thấy trở nên quá lớn
david_adler

Câu trả lời này có một sai sót nghiêm trọng đối với các mẫu lớn. Xác suất va chạm tăng tuyến tính với mỗi bước. Tôi đã đăng một giải pháp sử dụng Trình tạo thông số tuyến tính có O (1) chi phí bộ nhớ và các bước O (k) cần thiết để tạo k số. Điều này có thể được giải quyết hiệu quả hơn nhiều!
Thomas Lux,

Câu trả lời này chắc chắn tốt hơn nếu bạn muốn tạo một số chuỗi ngẫu nhiên theo thứ tự độ dài của chuỗi! Phương pháp LCG ít "ngẫu nhiên" hơn khi tạo ra nhiều trình tự duy nhất.
Thomas Lux,

"Chức năng này giải quyết cả hai vấn đề" Nó giải quyết vấn đề thứ hai như thế nào? Bạn vẫn không thể lấy 1000 mẫu từ dân số 2. Thay vì ném một ngoại lệ, bạn tạo ra một kết quả không chính xác; đó hầu như không phải là một giải pháp của "vấn đề" (mà thực sự không phải là một vấn đề để bắt đầu vì không hợp lý chút nào khi yêu cầu k mẫu duy nhất từ ​​một tập hợp n <k ).
kyrill

1

Bạn có thể sử dụng thư viện Numpy để trả lời nhanh như hình dưới đây -

Đoạn mã đưa ra liệt kê 6 số duy nhất trong phạm vi từ 0 đến 5. Bạn có thể điều chỉnh các thông số sao cho thoải mái.

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

Đầu ra

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

Nó không đặt bất kỳ ràng buộc nào như chúng ta thấy trong ngẫu nhiên. Ví dụ như được đề cập ở đây .

Mong cái này giúp được chút ít.


1

Câu trả lời được cung cấp ở đây hoạt động rất tốt đối với thời gian cũng như bộ nhớ nhưng phức tạp hơn một chút vì nó sử dụng các cấu trúc python nâng cao chẳng hạn như năng suất. Các câu trả lời đơn giản hơn hoạt động tốt trong thực tế nhưng, vấn đề với câu trả lời đó là nó có thể tạo ra nhiều nguyên giả mạo trước khi thực sự xây dựng các thiết lập cần thiết. Hãy thử với dân số: Kích thước = 1000, Kích thước mẫu = 999. Về lý thuyết, có khả năng nó không kết thúc.

Câu trả lời dưới đây giải quyết cả hai vấn đề, vì nó có tính xác định và phần nào hiệu quả mặc dù hiện tại không hiệu quả bằng hai câu kia.

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

trong đó các hàm getElem, percolateUp như được định nghĩa bên dưới

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

Cuối cùng, thời gian trung bình là khoảng 15ms cho một giá trị lớn của n như hình dưới đây,

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]

Bạn nghĩ rằng câu trả lời là phức tạp? Cái gì thế này ?! Và sau đó là câu trả lời khác , tạo ra nhiều "số nguyên giả". Tôi đã chạy triển khai của bạn với đầu vào ví dụ mà bạn đã cung cấp (dân số = 1000, mẫuSize = 999). Phiên bản của bạn gọi random.randinthàm 3996 lần, trong khi phiên bản còn lại là cca. 6000 lần. Đó không phải là một cải tiến lớn phải không?
kyrill

@kyrill, bạn đảm nhận câu trả lời này
aak318

1

Để có được một chương trình tạo ra một danh sách các giá trị ngẫu nhiên không trùng lặp có tính xác định, hiệu quả và được xây dựng với các cấu trúc lập trình cơ bản, hãy xem xét hàm extractSamples được định nghĩa bên dưới,

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

Ý tưởng cơ bản là theo dõi các khoảng thời gian intervalLst cho các giá trị có thể để từ đó chọn các phần tử bắt buộc của chúng tôi. Điều này là xác định theo nghĩa là chúng tôi được đảm bảo tạo ra một mẫu trong một số bước cố định (chỉ phụ thuộc vào populationSizesampleSize ).

Để sử dụng hàm trên để tạo danh sách yêu cầu của chúng tôi,

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

Chúng tôi cũng có thể so sánh với một giải pháp trước đó (đối với giá trị thấp hơn của Kích thước quần thể)

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

Lưu ý rằng tôi đã giảm populationSizegiá trị vì nó tạo ra Lỗi bộ nhớ cho các giá trị cao hơn khi sử dụng random.samplegiải pháp (cũng được đề cập trong các câu trả lời trước ở đâytại đây ). Đối với các giá trị trên, chúng ta cũng có thể quan sát thấy điều đó extractSamplestốt hơn so với random.samplecách tiếp cận.

Tái bút: Mặc dù cách tiếp cận cốt lõi tương tự như câu trả lời trước đây của tôi , có những sửa đổi đáng kể trong việc triển khai cũng như cách tiếp cận cùng với sự cải thiện về độ rõ ràng.


0

Một chức năng rất đơn giản cũng giải quyết được vấn đề của bạn

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]

"""

0

Vấn đề với các phương pháp tiếp cận dựa trên tập hợp ("nếu giá trị ngẫu nhiên trong các giá trị trả về, hãy thử lại") là thời gian chạy của chúng không được xác định do xung đột (yêu cầu lặp lại "thử lại" khác), đặc biệt khi một lượng lớn giá trị ngẫu nhiên được trả về từ phạm vi.

Một giải pháp thay thế không gây ra thời gian chạy không xác định này là:

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]

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)

1
Chào mừng bạn đến với Stackoverflow. Vui lòng giải thích câu trả lời của bạn tại sao và nó giải quyết vấn đề như thế nào để người khác có thể hiểu câu trả lời của bạn một cách dễ dàng.
octobus

Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do tại sao điều này giải quyết vấn đề sẽ thực sự giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều phiếu bầu hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định áp dụng. Từ đánh giá
double-beep

-1

Nếu bạn muốn đảm bảo rằng các số được thêm vào là duy nhất, bạn có thể sử dụng đối tượng Set

nếu sử dụng 2.7 trở lên hoặc nhập mô-đun bộ nếu không.

Như những người khác đã đề cập, điều này có nghĩa là các con số không thực sự ngẫu nhiên.


-1

để lấy mẫu số nguyên mà không thay thế giữa minvalmaxval:

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]

với 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]

Tại sao bạn lại tạo ra một hoán vị của một số lượng lớn các phần tử và sau đó chỉ chọn phần tử đầu tiên n_samplestrong số chúng? Lý do của bạn đằng sau cách tiếp cận này là gì? Bạn có thể giải thích những ưu điểm của cách tiếp cận của bạn so với bất kỳ câu trả lời nào trong số lượng lớn các câu trả lời hiện có (hầu hết là từ 8 năm trước)?
kyrill

thực sự câu trả lời của tôi có độ phức tạp tương tự như các câu trả lời được bình chọn hàng đầu khác và nhanh hơn vì nó sử dụng numpy. khác, các phương pháp được bình chọn nhiều nhất sử dụng random.shuffle, sử dụng Mersenne Twister, qhich chậm hơn nhiều so với các phương pháp được cung cấp bởi numpy (và có thể là jax). numpy và jax cho phép các thuật toán tạo số ngẫu nhiên khác. jax cũng cho phép biên dịch và phân biệt jit, có thể hữu ích cho việc phân biệt ngẫu nhiên. ngoài ra, liên quan đến một mảng "có thể lớn", một số câu trả lời được bình chọn nhiều nhất cũng làm điều tương tự random.shuffle, điều mà tôi không nghĩ là tội lỗi theo nghĩa tương đối hoặc thậm chí tuyệt đối
grisaitis

1
Không chắc bạn muốn nói gì khi " random.shufflesử dụng Mersenne Twister" - đó là sự xáo trộn của Fisher-Yates, như đã đề cập trong một số câu trả lời. Nó có độ phức tạp về thời gian tuyến tính vì vậy nó không thể tiệm cận chậm hơn các thuật toán được cung cấp bởi bất kỳ thư viện nào khác, không cần thiết hoặc cách khác. Nếu numpy nhanh hơn, đó chỉ là vì nó được nhúng trong C, nhưng điều này không đảm bảo tạo ra một hoán vị lớn (một hoán vị thậm chí có thể không vừa với bộ nhớ), chỉ để chọn một vài phần tử từ nó. Không có một single câu trả lời bên cạnh bạn mà thực hiện điều này.
kyrill

Xin lỗi, tôi đã đọc thấy rằng python ngẫu nhiên đã sử dụng Mersenne Twister làm prng. Bạn có nguồn để tôi có thể tìm hiểu thêm về Fisher Yates và vai trò trong random.shuffle không?
grisaitis

Đã có hai liên kết riêng biệt đến Wikipedia về hai câu trả lời riêng biệt ở đây. Nếu Wikipedia không phải là một nguồn đủ tốt cho bạn, có 14 tài liệu tham khảo ở cuối bài viết. Và sau đó là Google. cái đó có giúp ích không? Ồ, và randommô-đun được viết bằng Python, vì vậy bạn có thể dễ dàng xem nguồn của nó (hãy thử random.__file__).
kyrill

-3

Từ CLI trong win xp:

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

Ở Canada, chúng tôi có xổ số 6/49. Tôi chỉ bọc đoạn mã trên trong lotto.bat và chạy C:\home\lotto.bathoặc chỉ C:\home\lotto.

random.randintthường lặp lại một số, tôi sử dụng setvớirange(7) và sau đó rút ngắn nó thành độ dài 6.

Đôi khi nếu một số lặp lại nhiều hơn 2 lần thì độ dài danh sách kết quả sẽ nhỏ hơn 6.

CHỈNH SỬA: Tuy nhiên, random.sample(range(6,49),6)là cách chính xác để đi.


-3
import random
result=[]
for i in range(1,50):
    rng=random.randint(1,20)
    result.append(rng)

1
Bạn có thể giải thích cách này tránh trùng lặp không? Nó không rõ ràng từ kết xuất mã này.
Toby Speight

Nó không. print len(result), len(set(result)). Bạn sẽ mong đợi thấy rằng resultsẽ có các yếu tố duy nhất chỉ sau mỗi 1.0851831788708547256608362340568947172111832359638926... × 10^20lần thử.
Jedi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.