2013-12-10 59 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_sampler1test_sampler2从执行一些随机抽样2类对象。该类有一个属性random_inst,它是random.Random()类型的对象。文件seed1234包含TestSamplerrandom_inst的状态,如random.getstate()所返回的状态,当它被给予1234的种子时,您可以猜测seed7883是什么。我做的是我在终端中创建了一个TestSampler,给它一个随机种子1234,获得了rand_inst.getstate()的状态并保存到一个文件中。然后我重新创建了回归测试,并且始终获得相同的输出。

无论其

如上不会为test_sampler2工作相同的程序 - 无论我没有得到相同的数字随机序列。我正在使用python的random模块,我没有在其他地方导入它,但我在某些地方使用numpy(但不是numpy.random)。

test_sampler1test_sampler2之间唯一的区别是它们是从2个不同的文件创建的。我知道这是一个大问题,它完全依赖于我编写的代码,但我也不能简单地在这里粘贴~800行代码,我只是寻找一些我可能会搞砸的一般概念......

什么可能扰乱test_sampler2的随机数发生器的状态?

解决方案

有我的代码2个独立的问题:

我的脚本是一个命令行脚本后,我重构它使用Python的optparse图书馆,我发现,我为我的采样器设置种子,使用类似seed = sys.argv[1]这意味着我将种子设置为str,而不是int - seed可以采取任何hashabl e对象,我发现它很难。这解释了为什么如果我使用相同的种子,我会得到2个不同的序列 - 一个是如果我从命令行运行我的脚本,如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。为了解决这个问题,我只是将概率值和概率压缩在一起,按概率和tadaa排序 - 现在我总是得到相同的概率区间。

解决这两个问题后,代码按预期工作,即out2开始确定性地运行。

+0

我也会接受关于downvote的反馈......这个问题出了什么问题? – baibo

+0

为什么不使用'pickle.dump(random_inst,f1)'和'random_inst = pickle.load(f1)'而不是'eval'? –

+0

所以你说反复加载相同的种子文件给出了不同的序列?你使用的是什么版本的Python? –

回答

1

唯一可以更改random.Random实例状态的事件(除了内部Python错误)是调用该实例的方法。所以问题出在你还没有显示给我们。这里有一个小测试程序:

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.py上添加打印语句以找出正在做什么。有更聪明的方法可以做到这一点,但更好的方法是让它变得简单,以免最终调试调试代码。

+0

当我查看'random.py'的代码时,似乎正在使用Wichman-Hill随机数生成器,但文档说http://docs.python.org/2.6/library/random.html别的东西... – baibo

+0

你一定在看'WichmannHill'类,你不用它。类“随机”是你*使用的,并且是从'_random.Random'继承的。在Python 2.6中,反过来由'Modules/_randommodule.c'中的C代码定义,该文件也包含Mersenne Twister实现。 –

+0

我发现了错误,你是对的 - 这是我没有向你显示的东西,事实上,这不是我的随机种子设置的错。我会用错误方法的解决方案和代码更新我的文章。 – baibo