2010-04-10 16 views
20

Per recuperare i numeri casuali k da una matrice di dimensioni indeterminate si utilizza una tecnica chiamata campionamento del serbatoio. Qualcuno può evidenziare brevemente come accade con un codice di esempio?Campionamento serbatoio

+0

questione connessa http://stackoverflow.com/questions/54059/efficiently-selection-a-set-of-random-elements-da-a-linked-list –

+0

[Questa pagina] (http://blogs.msdn.com/spt/archive/2008/02/05/ reservoir-sampling.aspx) contiene una buona spiegazione con pseudo-codice. (La pagina di Wikipedia a cui ero originariamente collegato non è chiara, e lo pseudo-codice è incompleto.) –

+1

Ho scritto un post sul blog sull'esatta cosa un paio di mesi fa, che ha un'implementazione in C#: http://gregbeech.com/ blog/sampling-sequenze molto grandi La migliore descrizione di come funziona è stata trovata qui: http://gregable.com/2007/10/reservoir-sampling.html –

risposta

27

Io in realtà non avevo capito c'era un nome per questo, così ho dimostrato e realizzato questo da zero:

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 

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

Con una prova vicino alla fine.

+0

@Larry: dove si trova il 'accept con la parte di probabilità s/k' nel tuo codice? [citazione dall'algoritmo menzionato su http://blogs.msdn.com/spt/archive/2008/02/05/reservoir-sampling.aspx] – Lazer

+0

Per coincidenza, sembra che tra quell'articolo e il mio, usiamo le stesse variabili , ma per cose diverse. La mia "K" sembra essere la loro "S", e la mia "N" (in codice) sembra essere la loro "K". In altre parole, accetto le cose con probabilità 'K/N', dove N è il numero corrente di cose. – Larry

+0

quello che intendevo chiedere era come stavi implementando la probabilità nel tuo codice. Ad ogni modo, ora capisco. Grazie! – 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

Questa domanda ha già una risposta accettata da * anni * fa ... – alestanis

4

seguendo (1981) descrizione di Knuth più da vicino, Reservoir campionamento (Algoritmo R) potrebbe essere implementato come segue:

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

Qual è la differenza tra questo e [la risposta accettata] (http://stackoverflow.com/a/2612822/481584)? Penso che sia esattamente la stessa cosa, anche se questo codice è più elegante. –

+1

Può essere direttamente correlato alla ricerca pubblicata ([Knuth, 1981] (https://github.com/djtrack16/thyme/blob/master/computer%20science/Donald.E.Knuth.The.Art.of.Computer. Programming.Volume.2.pdf)), nel caso qualcuno sia interessato a una spiegazione più estesa o alla dimostrazione di Knuth. – sam

Problemi correlati