Nomor acak non-repetitif dalam numpy

92

Bagaimana cara menghasilkan nomor acak non-repetitif di numpy?

list = np.random.random_integers(20,size=(10))
Akademisi
sumber
Apa yang Anda maksud dengan "non-repetitive"? Bahwa urutan bilangan acak tidak pernah berulang? Ini tidak mungkin, karena keadaan generator bilangan acak harus sesuai dengan memori komputer yang terbatas. Atau maksud Anda tidak ada satu angka pun yang muncul dua kali?
Sven Marnach
5
Non-repetitive artinya Anda memiliki list tanpa duplikat.
Polinomial
2
Mungkin Anda membutuhkan permutasi acak? docs.scipy.org/doc/numpy/reference/generated/…
cyborg

Jawaban:

112

numpy.random.Generator.choicemenawarkan replaceargumen untuk diambil sampelnya tanpa penggantian:

from numpy.random import default_rng

rng = default_rng()
numbers = rng.choice(20, size=10, replace=False)

Jika Anda menggunakan NumPy di ​​bawah 1.17, tanpa GeneratorAPI, Anda dapat menggunakan random.sample()dari pustaka standar:

print(random.sample(range(20), 10))

Anda juga dapat menggunakan numpy.random.shuffle()dan mengiris, tetapi ini akan kurang efisien:

a = numpy.arange(20)
numpy.random.shuffle(a)
print a[:10]

Ada juga replaceargumen dalam numpy.random.choicefungsi legacy , tetapi argumen ini diimplementasikan secara tidak efisien dan kemudian dibiarkan tidak efisien karena jaminan stabilitas aliran bilangan acak, jadi penggunaannya tidak disarankan. (Ini pada dasarnya melakukan hal shuffle-and-slice secara internal.)

Sven Marnach
sumber
1
print random.sample (range (20), 10) tidak berfungsi dengan python 2.6 ?!
Academia
Masalahnya adalah karena konfigurasi Pydev yang buruk. Thks
Academia
1
Bagaimana jika n saya bukan 20, tetapi seperti 1000000, tetapi saya hanya membutuhkan 10 nomor unik darinya, apakah ada pendekatan yang lebih efisien memori?
mrgloom
2
@mrgloom Dalam Python 3, random.sample(range(n), 10))akan efisien bahkan untuk yang sangat besar n, karena rangeobjek hanyalah pembungkus kecil yang menyimpan nilai awal, henti, dan langkah, tetapi tidak membuat daftar lengkap bilangan bulat. Di Python 2, Anda bisa mengganti rangedengan xrangeuntuk mendapatkan perilaku serupa.
Sven Marnach
110

Saya pikir numpy.random.sampletidak berfungsi sekarang. Ini cara saya:

import numpy as np
np.random.choice(range(20), 10, replace=False)
strnam
sumber
26
Alih-alih range(n)(atau arange(n)) sebagai argumen pertama choice, itu setara dengan hanya lulus n, misalnya choice(20, 10, replace=False).
Josh Bode
1
Perhatikan bahwa np.random.choice(a, size, replace=False)sangat lambat untuk ukuran besar a- di komputer saya, sekitar 30 ms untuk a = 1M.
Matthew Rahtz
3
Untuk menghindari masalah memori waktu dan untuk sangat besar ndigunakan numpy.random.Generator.choice(dimulai dengan v1.17 numpy)
benbo
1
Kerugian utama yang saya lihat adalah np.random.choice tidak memiliki parameter sumbu -> hanya untuk array 1d.
Moosefeather
3

Bertahun-tahun kemudian, beberapa waktu untuk memilih 40000 dari 10000 ^ 2 (Numpy 1.8.1, imac 2.7 GHz):

import random
import numpy as np

n = 10000
k = 4
np.random.seed( 0 )

%timeit np.random.choice( n**2, k * n, replace=True )  # 536 µs ± 1.58 µs
%timeit np.random.choice( n**2, k * n, replace=False ) # 6.1 s ± 9.91 ms

# https://docs.scipy.org/doc/numpy/reference/random/index.html
randomstate = np.random.default_rng( 0 )
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=False )  # 766 µs ± 2.18 µs
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=True )   # 1.05 ms ± 1.41 µs

%timeit random.sample( range( n**2 ), k * n )          # 47.3 ms ± 134 µs

(Mengapa memilih 40000 dari 10.000 ^ 2? Untuk menghasilkan matriks scipy.sparse.random yang besar - penggunaan scipy 1.4.1 np.random.choice( replace=False ), slooooow.)

Tip of the hat untuk orang numpy.random.

denis
sumber
1

Anda bisa mendapatkan ini dengan menyortir juga:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)
Ben
sumber
0

Konversi set list Python dapat digunakan. 10 angka unik antara 0 hingga 20 dapat diperoleh sebagai:

import numpy as np
import random
unique_numbers=set()
while(len(unique_numbers)<10):
    unique_numbers.add(np.random.randint(0,20))

unique_numbers=list(unique_numbers)
random.shuffle(unique_numbers)
print(unique_numbers)
Ali Şentürk
sumber
-3

Cukup buat larik yang berisi rentang angka yang diperlukan, lalu kocok dengan berulang kali menukar angka acak dengan elemen ke-0 dalam larik. Ini menghasilkan urutan acak yang tidak mengandung nilai duplikat.

Polinomial
sumber
2
Sifat lain dari urutan acak yang dihasilkan adalah tidak terlalu acak .
Sven Marnach
@SvenMarnach - Untuk sebagian besar tujuan, ini cukup acak. Dia bisa menggunakan pendekatan acak ganda jika dia menginginkannya lebih acak.
Polinomial
Ini tidak ada gunanya. OP dapat menggunakan panggilan perpustakaan untuk melakukannya dengan benar. Mereka lebih mudah digunakan, berjalan lebih cepat dan lebih mudah dibaca daripada versi kustom. Saya tidak dapat memikirkan alasan apa pun mengapa saya harus menggunakan algoritme yang salah di sini hanya karena algoritme tersebut mungkin "cukup acak", jika menggunakan algoritme yang benar tidak ada kerugian apa pun.
Sven Marnach
@SvenMarnach - Cukup adil. Saya tidak tahu numpy, jadi saya hanya menawarkan solusi potensial.
Polinomial