2013-12-10 2 views
0

Мой вопрос - полная противоположность this one.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 'random_inst', которое было возвращено random.getstate(), когда было дано семя 1234, и вы можете догадаться, что такое seed7883. То, что я сделал, я создал TestSampler в терминале, дал ему случайное семя 1234, приобрел состояние с rand_inst.getstate() и сохранил его в файл. Затем я воссоздаю регрессионный тест, и я всегда получаю тот же результат.

ОДНАКО

Та же процедура, что и выше не работает test_sampler2 - все, что я не получаю ту же случайную последовательность чисел. Я использую модуль random python, и я не импортирую его нигде, но в некоторых местах я использую numpy (но не numpy.random).

Единственная разница между test_sampler1 и test_sampler2 заключается в том, что они созданы из 2 разных файлов. Я знаю, что это большое дело, и это полностью зависит от кода, который я написал, но я также не могу просто вставить здесь ~ 800 строк кода, я просто ищу какое-то общее представление о том, что я могу испортить ...

Что может быть скремблировать состояние генератора случайных чисел test_sampler2?

Решение

Были 2 отдельные проблемы с моим кодом:

Мой сценарий командной строки сценария и после того, как я реструктурировать его использовать optparse библиотеку питона я узнал, что Я устанавливал семя для моего пробоотборника, используя что-то вроде seed = sys.argv[1], что означало, что я устанавливал семя как str, а не int - seed может принимать любые хэши e, и я нашел это трудным путем. Это объясняет, почему я получал бы две разные последовательности, если бы использовал одно и то же семя - один, если я запустил свой сценарий из командной строки с помощью sth, например python sample 1234 #seed is 1234, и из моего файла unit_tests.py, когда я создам экземпляр объекта, например test_sampler1 = TestSampler(seed=1234).

У меня есть функция для дискретной выборки распределения, который я позаимствовал из here (посмотреть на принятый ответ).В коде отсутствует что-то фундаментальное: он все еще не детерминирован в том смысле, что если вы дадите ему те же значения и массив вероятностей, но преобразуетесь подстановкой (скажем, значения ['a','b'] и probs [0.1,0.9] и значения ['b','a'] и вероятности [0.9,0.1]) и семя установлено, и вы получите тот же случайный образец, скажем 0.3, по PRNG, но так как интервалы для ваших вероятностей разные, в одном случае вы получите b и в одном a. Чтобы исправить это, я просто связал значения и вероятности вместе, отсортированные по вероятности и тадаа - теперь я всегда получаю одинаковые интервалы вероятности.

После исправления обеих проблем код работал, как ожидалось, i.e. out2 начал детерминистически деваться.

+0

Я принимал бы обратную связь и в нисходящем направлении ... Что не так с этим вопросом? – baibo

+0

Почему бы не использовать 'pickle.dump (random_inst, f1)' и 'random_inst = pickle.load (f1)' вместо 'eval'? –

+0

Итак, вы говорите, что загрузка одного и того же файла семени снова и снова дает другую последовательность? Какую версию Python вы используете? –

ответ

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() 

Я не запускали, что весь день, но я уверен, я мог и никогда не увидеть провальную Assert ;-)

Кстати, это, безусловно, более общим для использования pickle для такого рода вещей, но это не решит вашу настоящую проблему. Проблема заключается не в получении или настройке состояния. Проблема в том, что что-то, что вы еще не нашли, вызывает методы на вашем экземпляре random.Random.

Хотя это серьезная боль в заднице, вы можете сделать может попробуйте добавить заявления печати random.py, чтобы узнать, что это делает. Есть более умные способы сделать это, но лучше держать его в грязи простым, чтобы вы не в конечном итоге отлаживали отладочный код.

+0

, когда я просматриваю код 'random.py', похоже, использует генератор случайных чисел Wichman-Hill, но документы говорят http://docs.python.org/2.6/library/random.html что-то еще ... – baibo

+0

Вы должны смотреть класс 'WichmannHill', который вы не используете.Класс 'Random' - это то, что вы * используете *, и которое наследуется от' _random.Random'. В Python 2.6 это, в свою очередь, определяется кодом C в модуле/_randommodule.c', файл которого также содержит реализацию Mersenne Twister. –

+0

Я нашел ошибку, и вы были правы - это было в чем-то, что я не показывал вам, и, по сути, это не было ошибкой моего случайного выбора семян. Я обновляю сообщение с помощью решения и кода неисправного метода. – baibo

Смежные вопросы