【发布时间】:2017-11-02 23:04:30
【问题描述】:
我希望能够在 Python 的标准 Random 和 numpy 的 np.random.RandomState 之间来回转换。这两个都使用 Mersenne Twister 算法,所以应该可以(除非他们使用该算法的不同版本)。
我开始研究这些对象的 getstate/setstate 和 get_state/set_state 方法。但我不确定如何转换它们的细节。
import numpy as np
import random
rng1 = np.random.RandomState(seed=0)
rng2 = random.Random(seed=0)
state1 = rng1.get_state()
state2 = rng2.getstate()
检查我看到的每个状态:
>>> print(state1)
('MT19937', array([0, 1, 1812433255, ..., 1796872496], dtype=uint32), 624, 0, 0.0)
>>> print(state2)
(3, (2147483648, 766982754, ..., 1057334138, 2902720905, 624), None)
第一个状态是一个大小为 5 的元组,带有 len(state1[1]) = 624。
第二个状态是一个大小为 3 的元组,len(state2[1]) = 625。看起来 state2 中的最后一项实际上是 state1 中的 624,这意味着数组实际上是相同的大小。到目前为止,一切都很好。这些似乎相当兼容。
不幸的是,内部数字没有明显的对应关系,因此种子 0 会导致不同的状态,这是有道理的,因为 rng1.rand() = .548 和 rng2.random() = .844。所以,算法似乎略有不同。
但是,我不需要它们完全对应。 我只需要能够确定地设置一个 rng 的状态,而不影响第一个的状态。
理想情况下,一旦我使用第一个的状态设置第二个的状态,而不调用任何随机方法,然后使用第二个设置第一个的状态,第一个状态将保持不变,但这是不是要求。
目前我有一个组合在一起的方法,它只是交换我可以从两个 rng 中提取的 624 长度列表。但是,我不确定这种方法是否有任何问题。任何对此主题更了解的人都可以提供一些启示吗?
这是我的方法,但我不确定它是否正确。
np_rng = np.random.RandomState(seed=0)
py_rng = random.Random(0)
# Convert python to numpy random state (incomplete)
py_state = py_rng.getstate()
np_rng = np.random.RandomState(seed=0)
np_state = np_rng.get_state()
new_np_state = (
np_state[0],
np.array(py_state[1][0:-1], dtype=np.uint32),
np_state[2], np_state[3], np_state[4])
np_rng.set_state(new_np_state)
# Convert numpy to python random state (incomplete)
np_state = np_rng.get_state()
py_rng = random.Random(0)
py_state = py_rng.getstate()
new_py_state = (
py_state[0], tuple(np_state[1].tolist() + [len(np_state[1])]),
py_state[1]
)
py_rng.setstate(new_py_state)
编辑:
进行一些调查后,我检查了 10 次调用随机函数时状态发生的情况。
np_rng = np.random.RandomState(seed=0)
py_rng = random.Random(0)
for i in range(10):
np_rng.rand()
npstate = np_rng.get_state()
print([npstate[0], npstate[1][[0, 1, 2, -2, -1]], npstate[2], npstate[3], npstate[4]])
for i in range(10):
py_rng.random()
pystate = py_rng.getstate()
print([pystate[0], pystate[1][0:3] + pystate[1][-2:], pystate[2]])
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 2, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 4, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 6, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 8, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 10, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 12, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 14, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 16, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 18, 0, 0.0]
['MT19937', array([2443250962, 1093594115, 1878467924, 2648828502, 1678096082], dtype=uint32), 20, 0, 0.0]
[3, (1372342863, 3221959423, 4180954279, 418789356, 2), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 4), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 6), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 8), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 10), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 12), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 14), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 16), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 18), None]
[3, (1372342863, 3221959423, 4180954279, 418789356, 20), None]
我希望每个元组中的第一项只是他们正在使用的算法的版本。
有趣的是,624 个整数似乎没有变化。总是这样吗?
但是,我仍然不确定 Python 版本中最后的 None 是什么意思,而最后的 2 数字在 numpy 版本中是什么意思。
【问题讨论】:
-
你能解释一下这个问题的根本原因吗?
-
我有一个我想播种的算法管道。一些函数使用 python 的 rng,而另一些函数使用 numpy 的 rng。有时一个用于另一个的内循环。我必须将 rng's 传递给使用它的每个函数,所以我想要一种方法,可以在它们之间无缝地来回转换,而不会做一些混乱的事情,比如用另一个的随机值播种。
-
我需要确保输出在输入上是确定性的。我正在使用的函数的结果是一个数据样本,并且该样本具有关联的哈希值。如果散列不同,则将运行非常耗时的索引算法,否则使用缓存版本。 Mark Dickinson 的回答正是我所需要的。
标签: python numpy random mersenne-twister numpy-random