2010-04-10 19 views
20

Para recuperar k números aleatorios de una matriz de tamaño indeterminado utilizamos una técnica llamada muestreo de yacimientos. ¿Alguien puede destacar brevemente cómo sucede con un código de muestra?Muestreo de yacimientos

+0

pregunta relacionada http://stackoverflow.com/questions/54059/selection-a-set-of-random-elements-from-a-linked-list –

+0

[Esta página] (http://blogs.msdn.com/spt/archive/2008/02/05/ reservoir-sampling.aspx) contiene una buena explicación con pseudo-código. (La página de Wikipedia a la que originalmente me vinculé no está clara, y el pseudocódigo está incompleto). –

+1

Escribí una entrada de blog sobre el tema exacto hace un par de meses, que tiene una implementación de C#: http://gregbeech.com/ blog/sampling-very-large-sequences La mejor descripción de cómo funciona que he encontrado está aquí: http://gregable.com/2007/10/reservoir-sampling.html –

Respuesta

27

En realidad no sabía que había un nombre para esto, así que probé e implementé esto desde cero:

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 

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

Con una prueba cerca del final.

+0

@Larry: ¿Dónde está el 'aceptar con probabilidad s/k' en tu código? [cita del algoritmo mencionado en http://blogs.msdn.com/spt/archive/2008/02/05/reservoir-sampling.aspx] – Lazer

+0

Por coincidencia, parece que entre ese artículo y el mío, usamos las mismas variables , pero para cosas diferentes Mi "K" parece ser su "S", y mi "N" (en el código) parece ser su "K". En otras palabras, acepto cosas con la probabilidad 'K/N', donde N es el conteo actual de cosas. – Larry

+0

lo que quise preguntar es cómo estaba implementando la probabilidad en su código. De todos modos, ahora lo entiendo. ¡Gracias! – 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

Esta pregunta ya tiene una respuesta aceptada de * years * ago ... – alestanis

4

Siguiendo (1981) Descripción de Knuth más de cerca, embalse de muestreo (algoritmo R) podría implementarse de la siguiente manera:

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

¿Cuál es la diferencia entre esto y [la respuesta aceptada] (http://stackoverflow.com/a/2612822/481584)? Creo que esto es exactamente lo mismo, incluso si este código es más elegante. –

+1

Puede estar directamente relacionado con la investigación publicada ([Knuth, 1981] (https://github.com/djtrack16/thyme/blob/master/computer%20science/Donald.E.Knuth.The.Art.of.Computer. Programming.Volume.2.pdf)), en caso de que alguien esté interesado en una explicación más extensa o la prueba de Knuth. – sam

Cuestiones relacionadas