2014-04-09 17 views
5

Mam ogromny np.array nazwie arr z wartości N i wybrać 10% tych wartości losowo przez:Odwrócić losowy wybór kluczy w numpy tablicy

choice=random.sample(range(N), int(N*percent)) # percent has values 0-1 
newarr=arr[choice] 

N może być ponad 2 mln wartości.

Właściwie potrzebuję również tablicy z pozostałymi 90% wartości. W tej chwili używam następującego, który jest bardzo powolny:

def buildRevChoice(choice, nevents): 
     revChoice=[] 
     for i in range(N): 
      if not i in choice: 
       revChoice.append(i) 
     return revChoice 

Czy możesz wymyślić metodę, aby to wzmocnić?

+0

Szybka optymalizacja: W 'buildRevChoice', utwórz' set' z 'choice', aby przyspieszyć wyszukiwanie. –

+1

W ogóle nie używaj pętli Pythona do dużych tablic, jeśli potrzebujesz wydajności. Użyj funkcjonalnego programowania Pythona/numpy i wektoryzacji numpy. –

+0

Tak, wiem, ale nie znalazłem innego rozwiązania dla każdego google. Nie mogłem wymyślić rozsądnej frazy wyszukiwania. – user575736

Odpowiedz

6

Możesz po prostu random.shuffle listę, a następnie podzielić go, jak chcesz.

def choice(N, percent): 
    tmp = range(N) 
    random.shuffle(tmp) 
    cut = int(N * percent) 
    return tmp[:cut], tmp[cut:] 

a dostaniesz swoje dwie listy, pierwszy zawierający wybrańców i drugi zawierający resztę.

+2

niezłe rozwiązanie; chociaż jestem nieco nieufny wobec wykonania random.shuffle. Potencjalnie, random.permutation ma lepszą wydajność. I w zależności od tego, w jaki sposób jest to zaimplementowane, np.argsort (random.randint()) może być jeszcze szybszym sposobem wygenerowania indeksu permutacji. –

+0

@EcocoHoogendoorn Nie pracowałem używając 'numpy', więc wiem tylko podstawowy python :) Czy algorytm O (n) Fisher Yates Shuffle byłby dobrym wyborem do tasowania? – 0605002

+0

Każdy algorytm, który sam wdrożysz, będzie złym wyborem, chyba że masz zamiar napisać rozszerzenie C. Zauważ, że mam przetasowanie porównawcze; Wyobrażam sobie, że najbardziej losowy algorytm shuffle na miejscu niekoniecznie jest najbardziej wydajny. –

2

Jeśli masz problem z obciążeniem pamięci w macierzy masowej, wydaje się, że jest to szybsze niż wybieranie innych wartości przez indeks i zachowuje kolejność elementów w are. Oto co mam z synchronizacją z ipython Notebook:

N = 2000000 
arr = random.random(N) 
percent = 0.10 

Moje rozwiązanie:

%% timeit 
choice = random.choice(N, N*percent) 
mask = zeros_like(arr, bool) 
mask[choice] = True 
newarr = arr[mask] 
revchoice = arr[~mask] 

10 pętle, najlepiej z 3: 18.1 ms na pętli

0605002 za rozwiązanie:

tmp = range(N) 
random.shuffle(tmp) 
cut = int(N * percent) 
newarr, revchoice = tmp[:cut], tmp[cut:] 

1 pętle, najlepiej 3: 603 ms na pętlę

+0

Dziękuję bardzo, to są dwa bardzo dobre rozwiązania, sprawdzę, który z nich jest szybszy. Nie jestem przyzwyczajony do problemów z pamięcią. W takim przypadku nie powinienem używać masek? – user575736

+1

To rozwiązanie (i drugie przez 0605002) używa tablicy o tym samym rozmiarze co 'arr'. Więc jeśli twoja macierz jest w połowie tak duża, jak dostępna pamięć, nie będziesz mieć wystarczająco dużo miejsca, aby utworzyć maskę. Jeśli unikniesz budowania maski, możesz uzyskać o 10% więcej pamięci dla tablicy indeksów. 2 miliony punktów to jednak nie tyle. – chthonicdaemon

+1

Zaktualizowałem moją odpowiedź z timingami. Moje rozwiązanie jest o rząd wielkości szybsze. – chthonicdaemon