2012-01-26 21 views
12

Me gustaría una función que pueda generar una secuencia de valores pseudoaleatoria, pero para que esa secuencia sea repetible en cada ejecución. Los datos que quiero tienen que estar razonablemente distribuidos aleatoriamente en un rango dado, no tiene que ser perfecto.Cómo generar una secuencia de números aleatorios repetibles?

Quiero escribir un código que ejecutará pruebas de rendimiento basadas en datos aleatorios. Me gustaría que los datos sean los mismos para cada prueba, en cada máquina, pero no quiero tener que enviar los datos aleatorios con las pruebas por razones de almacenamiento (podría terminar siendo muchos megabytes).

La biblioteca para el módulo random no parece decir que la misma semilla siempre dará la misma secuencia en cualquier máquina.

EDITAR: Si va a sugerir que sembrar los datos (como dije antes), proporcione la documentación que dice que el enfoque es válido y funcionará en una variedad de máquinas/implementaciones.

EDITAR: CPython 2.7.1 y PyPy 1.7 en Mac OS X y CPython 2.7.1 y CPython 2.52 = .2 Parece que Ubuntu da los mismos resultados. Aún así, no hay documentos que estipulen esto en blanco y negro.

¿Alguna idea?

+2

¿Ha intentado * generar * una secuencia con una semilla dada varias veces? – bdares

+0

Solo tengo una computadora y un sistema operativo, por lo que no puedo probar esto de manera confiable. – Joe

+0

Como creo, la pregunta fundamental es "¿para qué?" Si es un cifrado, es una muy mala idea y no lo hagas. Debes escribir "por qué". – theWalker

Respuesta

4

La documentación no indica explícitamente que proporcionar una semilla siempre garantizará los mismos resultados, pero eso está garantizado con la implementación de Python al azar basado en el algoritmo que se utiliza.

De acuerdo con la documentación, Python usa el Mersenne Twister como generador central. Una vez que este algoritmo es sembrado, no obtiene ningún resultado externo que pueda cambiar las llamadas subsiguientes, por lo tanto, déle la misma semilla y obtendrá los mismos resultados .

Por supuesto, también puede observar esto estableciendo una semilla y generando grandes listas de números aleatorios y verificando que son iguales, pero entiendo que no quiero confiar solo en eso.

No he comprobado otras implementaciones de Python además de CPython, pero dudo mucho que implementen el módulo aleatorio usando un algoritmo completamente diferente.

+0

Eso es lo que pensé. Probablemente termine haciendo esto como la peor solución. – Joe

+0

Incluso si usaran un algoritmo completamente diferente, si diera el mismo valor inicial al mismo algoritmo pseudoaleatorio, escupirá la misma secuencia de números: usted podría tener problemas si quisiera probar en dos implementaciones diferentes de python que usó un algoritmo diferente pero eso es todo. Pero como yo entiendo los documentos, también garantizan el algoritmo subyacente, así que todo está bien. – Voo

+0

Se me ocurre que aún puede obtener resultados diferentes si tiene un Mersenne Twister de 32 bits frente a un Mersenne Twister de 64 bits – DrRobotNinja

6

Especifique una semilla para el generador de números aleatorios. Si proporciona la misma semilla, sus números aleatorios también deberían ser los mismos.

http://docs.python.org/library/random.html#random.seed

+0

Eso es lo que pensé, pero como dije en la pregunta, no puedo ver ninguna documentación que respalde esto. – Joe

+1

¿Has probado usar la misma semilla y observar la salida? – Oleksi

+2

http://www.tutorialspoint.com/python/number_seed.htm –

4

Usando random.seed (...) Se puede generar una secuencia repetible. Una demostración:

import random 

random.seed(321) 
list1 = [random.randint(1,10) for x in range(5)] 

random.seed(321) 
list2 = [random.randint(1,10) for x in range(5)] 

assert(list1==list2) 

Esto funciona porque random.seed (...) no es verdaderamente aleatorio: es pseudo-aleatorio, en el que los números sucesivos se producen permutando alguna máquina de estados, dada una condición inicial de partida, el ' semilla'.

0

he intentado lo siguiente:

import random 
random.seed(1) 
random.random() 
random.random() 
random.random() 

random.seed(1) 
random.random() 
random.random() 
random.random() 

que han entrado en cada línea en la CLI a varias velocidades más varias veces. Produjo los mismos valores cada vez.

4

Si la calidad de los números aleatorios no es tan crítica como la reproducibilidad del todo-plataformas, puede utilizar uno de los tradicionales linear congruential generators:

class lcg(object): 
    def __init__(self, seed=1): 
     self.state = seed 

    def random(self): 
     self.state = (self.state * 1103515245 + 12345) & 0x7FFFFFFF 
     return self.state 

Dado que este se codifica en su programa utilizando la aritmética de enteros , debe ser determinísticamente repetible en cualquier plataforma razonable.

+0

Brilliant, eche un vistazo a eso. – Joe

20

Para este propósito, he usado una repetición de hash MD5, ya que la intención de una función hash es una transformación multiplataforma uno-a-uno, por lo que siempre será la misma en diferentes plataformas.

import md5 

def repeatable_random(seed): 
    hash = seed 
    while True: 
     hash = md5.md5(hash).digest() 
     for c in hash: 
      yield ord(c) 

def test(): 
    for i, v in zip(range(100), repeatable_random("SEED_GOES_HERE")): 
     print v 

Salida:

184 207 76 134 103 171 90 41 12 142 167 107 84 89 149 131 142 43 241 211 224 157 47 59 34 233 41 219 73 37 251 194 15 253 75 145 96 80 39 179 249 202 159 83 209 225 250 7 69 218 6 118 30 4 223 205 91 10 122 203 150 202 99 38 192 105 76 100 117 19 25 131 17 60 251 77 246 242 80 163 13 138 36 213 200 135 216 173 92 32 9 122 53 250 80 128 6 139 49 94 

En esencia, el código tendrá su semilla (cualquier cadena válida) y repetidamente hash, lo que genera números enteros de 0 a 255.

+0

¡Esa es una idea brillante! – Joe

9

Hay diferencias de plataforma , así que si mueves tu código entre diferentes plataformas, elegiré el método que describió DrRobotNinja.

Por favor, eche un vistazo al siguiente ejemplo. Python en mi máquina de escritorio (64 bits de Ubuntu con un Core i7, Python 2.7.3) me da el siguiente:

> import random 
> r = random.Random() 
> r.seed("test") 
> r.randint(1,100) 
18 

Pero si corro el mismo código en mi Frambuesa Pi (Raspbian en ARM11), I llegar aa resultado diferente (para la misma versión de Python)

> import random 
> r = random.Random() 
> r.seed("test") 
> r.randint(1,100) 
34 
+0

¡Interesante! Gracias por señalar esto. – Joe

+0

No sé si esto es un comportamiento documentado. Parece extraño que esto dependa de la plataforma, cuando una parte tan grande de la biblioteca estándar de Python está diseñada para funcionar en varias plataformas. Tal vez debería presentar un error con el equipo de Python? – Joppe

+0

Esa es una buena idea (después de revisar primero los informes de errores). Si no es un error, habrá una buena explicación de por qué. – Joe

5

también una respuesta por qué el ejemplo de this answer no producir resultados distintos en diferentes máquinas:

Se debe a que cuando se siembra el generador aleatorio la semilla tiene ser un número entero. Si siembra el generador con un número no entero, primero tiene que ser hash. Las funciones de hash en sí mismas no son independientes de la plataforma (obviamente al menos no todas, corrígeme si sabes más).

Para unir todo: Python usa un generador de números pseudoaleatorio. Por lo tanto, cuando se inicia desde el mismo estado, la secuencia producida de números aleatorios siempre será la misma, independientemente de la plataforma. Es solo un algoritmo deteminista sin más información del mundo exterior.

Esto significa: siempre que inicialice su generador aleatorio con el mismo estado, producirá la misma secuencia de números. Llegar al mismo estado se puede hacer usando la misma semilla entera o guardando y volviendo a aplicar el estado antiguo (random.getstate() y random.setstate()).

+0

Esto parece una respuesta genuina, aunque parcial, y ciertamente agrega información. ¡Si yo fuera tú, eliminaría la disculpa en la parte superior! – Joe

+0

Comenzó mucho más corto pero se convirtió en una respuesta elaborada, por lo que tiene razón, y lo eliminé/reformulé. –

Cuestiones relacionadas