2010-04-10 11 views
20

Aby pobrać k losowych liczb z tablicy o nieokreślonym rozmiarze, używamy techniki zwanej próbkowaniem zbiorników. Czy ktokolwiek może krótko podkreślić, jak to się dzieje w przypadku przykładowego kodu?Próbkowanie zbiorników

+0

pokrewne pytanie http://stackoverflow.com/questions/54059/efektywny wybór-losowy-elementów-z-połączonej listy –

+0

[Ta strona] (http://blogs.msdn.com/spt/archive/2008/02/05/ reservoir-sampling.aspx) zawiera dobre objaśnienie z pseudokodem. (Strona, do której pierwotnie linkowałem, jest niejasna, a pseudo-kod jest niekompletny.) –

+1

Napisałem wpis na blogu o tym, co kilka miesięcy temu, który ma implementację C#: http://gregbeech.com/ blog/sampling-very-large-sequence Najlepszy opis tego, jak to działa, znajduje się tutaj: http://gregable.com/2007/10/reservoir-sampling.html –

Odpowiedz

27

I rzeczywiście nie zdawali sobie sprawy było imię tego, więc to udowodnione i realizowane od podstaw:

import random 
def random_subset(iterator, K): 
    result = [] 
    N = 0 

    for item in iterator: 
     N += 1 
     if len(result) < K: 
      result.append(item) 
     else: 
      s = int(random.random() * N) 
      if s < K: 
       result[ s ] = item 

    return result 

Od: http://web.archive.org/web/20141026071430/http://propersubset.com:80/2010/04/choosing-random-elements.html

z dowodem blisko końca.

+0

@Larry: Gdzie jest 'accept to z prawdopodobieństwem s/k "częścią twojego kodu? [cytat z algorytmu wymienionego na http://blogs.msdn.com/spt/archive/2008/02/05/reservoir-sampling.aspx] – Lazer

+0

Przez przypadek wydaje mi się, że między tym artykułem a moim używamy tych samych zmiennych , ale na różne rzeczy. Moje "K" wydaje się być ich "S", a moje "N" (w kodzie) wydaje się być ich "K". Innymi słowy, akceptuję rzeczy z prawdopodobieństwem 'K/N', gdzie N jest aktualną liczbą rzeczy. – Larry

+0

co miałem zamiar zapytać, to w jaki sposób wprowadziłeś prawdopodobieństwo w swoim kodzie. Tak czy inaczej, teraz rozumiem. Dzięki! – Lazer

0

Java

import java.util.Random; 

public static void reservoir(String filename,String[] list) 
{ 
    File f = new File(filename); 
    BufferedReader b = new BufferedReader(new FileReader(f)); 

    String l; 
    int c = 0, r; 
    Random g = new Random(); 

    while((l = b.readLine()) != null) 
    { 
     if (c < list.length) 
      r = c++; 
     else 
      r = g.nextInt(++c); 

     if (r < list.length) 
      list[r] = l; 

     b.close();} 
} 
+2

To pytanie już ma akceptowaną odpowiedź od * lat * temu ... – alestanis

4

Po Knutha (1981) opis dokładniej, zbiornik Sampling (algorytm R) mogą być realizowane w następujący sposób:

import random 

def sample(iterable, n): 
    """ 
    Returns @param n random items from @param iterable. 
    """ 
    reservoir = [] 
    for t, item in enumerate(iterable): 
     if t < n: 
      reservoir.append(item) 
     else: 
      m = random.randint(0,t) 
      if m < n: 
       reservoir[m] = item 
    return reservoir 
+0

Jaka jest różnica między tą a [zaakceptowaną odpowiedzią] (http://stackoverflow.com/a/2612822/481584)? Myślę, że to dokładnie to samo, nawet jeśli ten kod jest bardziej elegancki. –

+1

Może to być bezpośrednio związane z opublikowanymi badaniami ([Knuth, 1981] (https://github.com/djtrack16/thyme/blob/master/computer%20science/Donald.E.Knuth.The.Art.of.Computer. Programming.Volume.2.pdf)), na wypadek gdyby ktoś był zainteresowany bardziej rozszerzonym wyjaśnieniem lub dowodem Knutha. – sam

Powiązane problemy