Python что-то сбрасывает мое случайное семя
Мой вопрос - полная противоположность этому.
Это выдержка из моего тестового файла
f1 = open('seed1234','r')
f2 = open('seed7883','r')
s1 = eval(f1.read())
s2 = eval(f2.read())
f1.close()
f2.close()
####
test_sampler1.random_inst.setstate(s1)
out1 = test_sampler1.run()
self.assertEqual(out1,self.out1_regress) # this is fine and passes
test_sampler2.random_inst.setstate(s2)
out2 = test_sampler2.run()
self.assertEqual(out2,self.out2_regress) # this FAILS
Некоторая информация -
test_sampler1
а также test_sampler2
являются 2 объектами из класса, который выполняет некоторую стохастическую выборку. У класса есть атрибут random_inst
который является объектом типа random.Random()
, Файл seed1234
содержит TestSampler
"s random_inst
как возвращено random.getstate()
когда ему дали семя 1234
и вы можете догадаться, что seed7883
является. Что я сделал, я создал TestSampler
в терминале, дал ему случайное семя 1234
, приобрел государство с rand_inst.getstate()
и сохранить его в файл. Затем я воссоздаю регрессионный тест и всегда получаю один и тот же результат.
ТЕМ НЕ МЕНИЕ
Та же процедура, что и выше, не работает для test_sampler2
- что бы я не получал одинаковую случайную последовательность чисел. Я использую питона random
модуль, и я не импортирую его куда-либо еще, но я использую numpy
в некоторых местах (но не numpy.random
).
Единственная разница между test_sampler1
а также test_sampler2
является то, что они созданы из 2 разных файлов. Я знаю, что это большое дело, и оно полностью зависит от кода, который я написал, но я также не могу просто вставить здесь ~800 строк кода, я просто ищу общее представление о том, что я могу испортить...
Что может карабкаться test_sampler2
генератор случайных чисел?
Решение
С моим кодом было две отдельные проблемы:
1
Мой сценарий является сценарием командной строки, и после того, как я реорганизовал его для использования Python optparse
Библиотека я обнаружил, что я устанавливал семя для моего сэмплера, используя что-то вроде seed = sys.argv[1]
Это означало, что я собирался стать str
не int
- seed
может взять любой хешируемый объект и я нашел его трудным путем. Это объясняет, почему я получил бы 2 разные последовательности, если бы использовал одно и то же семя - одну, если я запускаю свой скрипт из командной строки с помощью команды sth python sample 1234 #seed is 1234
и из моего unit_tests.py
файл, когда я хотел бы создать экземпляр объекта, как test_sampler1 = TestSampler(seed=1234)
,
2
У меня есть функция для дискретной выборки распределения, которую я позаимствовал отсюда (посмотрите на принятый ответ). В коде отсутствовало что-то фундаментальное: оно все еще было недетерминированным в том смысле, что если вы дадите ему тот же массив значений и вероятностей, но трансформируется перестановкой (скажем, значениями) ['a','b']
и пробы [0.1,0.9]
и ценности ['b','a']
и вероятности [0.9,0.1]
) и семя будет установлено, и вы получите тот же случайный образец, скажем, 0.3
PRNG, но так как интервалы для ваших вероятностей разные, в одном случае вы получите b
и в одном a
, Чтобы исправить это, я просто сжал значения и вероятности вместе, отсортированные по вероятности и тадаа - теперь я всегда получаю одинаковые интервалы вероятности.
После исправления обеих проблем код работал как ожидалось, т.е. out2 начал вести себя детерминистически.
1 ответ
Единственная вещь (кроме внутренней ошибки Python), которая может изменить состояние random.Random
Экземпляр вызывает методы в этом экземпляре. Таким образом, проблема заключается в том, что вы не показали нам. Вот небольшая тестовая программа:
from random import Random
r1 = Random()
r2 = Random()
for _ in range(100):
r1.random()
for _ in range(200):
r2.random()
r1state = r1.getstate()
r2state = r2.getstate()
with open("r1state", "w") as f:
print >> f, r1state
with open("r2state", "w") as f:
print >> f, r2state
for _ in range(100):
with open("r1state") as f:
r1.setstate(eval(f.read()))
with open("r2state") as f:
r2.setstate(eval(f.read()))
assert r1state == r1.getstate()
assert r2state == r2.getstate()
Я не бегал так весь день, но держу пари, что смогу и никогда не увижу провального утверждения;-)
Кстати, это, конечно, чаще используется pickle
для такого рода вещей, но это не решит вашу настоящую проблему. Проблема не в получении или настройке состояния. Проблема в том, что то, что вы еще не нашли, вызывает методы на вашем random.Random
экземпляр (ы).
Хотя это очень сложно сделать, попробуйте добавить операторы печати к random.py
чтобы выяснить, что делает это. Существуют более умные способы сделать это, но лучше сохранить их простыми, чтобы в итоге вы не отладили код отладки.