2011-01-31 5 views
5

Potrzebuję próbki, bez wymiany, spośród wszystkich możliwych krotek liczb od range(n). Oznacza to, że mam kolekcję (0,0), (0,1), ..., (0, n), (1,0), (1,1), ..., (1, n), ..., (n, 0), (n, 1), (n, n) i próbuję pobrać próbkę k tych elementów. Mam nadzieję, że nie będę wyraźnie budować tej kolekcji.python: pobieranie próbek bez zamiany z siatki 2D

Wiem, że random.sample(range(n), k) jest prosty i efektywny, gdy potrzebuję próbki z sekwencji liczb, a nie krotek liczb.

Oczywiście, mogę jawnie zbudować listę zawierającą wszystkie możliwe krotki (n * n = n^2), a następnie zadzwonić pod numer random.sample. Ale to prawdopodobnie nie jest wydajne, jeśli k jest znacznie mniejsze niż n^2.

Nie jestem pewien, czy rzeczy działają tak samo w Pythonie 2 i 3 pod względem wydajności; Używam Pythona 3.

+2

krotki są sekwencjami, więc zdanie „potrzebował próbkę z sekwencji liczb zamiast krotek liczb.” nie ma sensu. Masz na myśli, że potrzebujesz próbki z sekwencji krotek? W tym przypadku nie jest jasne, jak te krotki wyglądają. –

+0

Twój kod ('random.sample (range (n), k)' działa i jest poprawny dla wszystkich sekwencji, krotek, list, ciągów znaków i dowolnej podklasy 'collections.Sequence'. Czy próbowałeś już swojego kodu? ? –

+0

@Regebro: 'próbka z krotek' = 'próbka k krotek z sekwencji n krotek'. "próbka z sekwencji" = "próbka k elementów z sekwencji n elementów". Zamierzam edytować pytanie, by wyjaśnić. @ S.Lott: Chciałem powiedzieć, że nie mogę odnieść się do sekwencji ((0,0), (0,1), (0,2), (1,0), (1,1) , (1,2), (2,0), (2,1), (2,2)) jako prosty "zakres", na którym mogę po prostu zastosować "próbkę". – max

Odpowiedz

6

W zależności od tego, ile z nich wybierzesz, najprościej będzie po prostu śledzić, co już wybrałeś (przez set), a następnie ponownie wybrać, aż otrzymasz coś których już nie wybrałeś.

Inną opcją jest po prostu użyć kilka prostych matematyki:

numbers_in_nxn = random.sample(range(n*n), k) # Use xrange in Python 2.x 
tuples_in_nxn = [divmod(x,n) for x in numbers_in_nxn] 
+0

Myślę, że chodziło o 'random.sample (range (n * n), k)' ponieważ to właśnie pisałem, gdy zdałem sobie sprawę, że umieściłeś tę część. –

+0

+1 Druga opcja wydaje mi się idealna (po zamianie 'n * n' na' range (n * n) ', a' 100' na 'n'). Nie mogę myśleć, kiedy rysunek z zestawu może być lepszy, biorąc pod uwagę, że "próbka" jest uważana za wysoce wydajną. – max

+1

Możesz zastąpić '(x% n, x // n)' 'divmod (x, n)'. – Kabie

0

Bez próbuje (bez Pythona pod ręką):

random.shuffle(range(n))[:k] 

zobaczyć komentarze. Nie spać wystarczająco ...

+0

To nie daje krotek w 'n' x' n', ponieważ nigdy by nie dało, powiedz '(1,1)'. – Amber

+0

Ale co oznacza "bez wymiany"? Ach, teraz widzę. k różnych krotek o długości n. – Howard

0

Mówisz:

Oczywiście, mogę jednoznacznie zbudować listę zawierającą wszystkie możliwe (n * n = n^2) krotki, a następnie zadzwonić losowa próbka. Ale to prawdopodobnie jest nieefektywne, jeśli wartość k jest znacznie mniejsza niż niż n^2.

Cóż, jak o budowaniu krotki po zostały losowo jeden? Tj., Jeśli możesz zbudować krotki, zanim losowo wybierzesz, który z nich wybierzesz, możesz najpierw wybrać zbiór i budynek.

Nie rozumiem, w jaki sposób krotki mają wyglądać, ale tutaj jest przykładem, choć zdaję sobie sprawę, twoi krotki są tej samej długości, to pokazuje zasadę:

zamiast robić to:

>>> import random 
>>> all_sequences = [range(x) for x in range(10)] 
>>> all_sequences 
[[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7, 8]] 
>>> random.sample(all_sequences, 3) 
[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6, 7, 8]] 

można by to zrobić:

>>> import random 
>>> selection = random.sample(range(10), 3) 
>>> [range(x) for a in selection] 
[[0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8]]