我希望能够在Python的标准Random和numpy之间来回转换随机状态. 这两种算法都使用Mersenne-Twister算法,因此应该是可能的(除非他们使用不同版本的该算法)。在
我开始研究这些对象的getstate/setstate和get\u state/set\u 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()
检查我看到的每一个州:
^{pr2}$第一个状态是一个大小为5的元组,其len(state1[1]) = 624
。在
第二种状态是一个大小为3的元组,其值为len(state2[1]) = 625
。看起来state2中的最后一项实际上是state1中的624,这意味着数组实际上大小相同。到现在为止,一直都还不错。这些似乎是合情合理的。在
不幸的是,内部数没有明显的对应关系,所以0的种子会产生不同的状态,这是有意义的,因为rng1.rand() = .548
和{
但是,我不需要它们完全对应。我只需要能够确定地设置一个rng与另一个rng的状态,而不影响第一个rng的状态。
理想情况下,一旦我使用第一个状态设置第二个状态,而不调用任何随机方法,然后使用第二个状态设置第一个状态,第一个状态将保持不变,但这不是一个要求。在
目前我有一个hacked together方法,它只交换我可以从两个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个整数似乎没有改变。总是这样吗?在
但是,我仍然不确定final None在Python版本中的含义,final 2 number在numpy版本中是什么意思。在
NumPy
RandomState
状态的形式是documented:最后两个条目引用标准正态偏差生成器的状态:NumPy usesThe Box–Muller transform,它成对生成这些偏离。因此,对gaussian生成器的第一次调用产生两个值,返回第一个值,然后将第二个值存储起来以供以后使用。然后,第二个调用检索第二个值。因此,我们在这里有额外的状态,需要存储和检索。在
Python
Random
状态的形式没有记录,但是很容易从source中提取出来。从CPython 3.6.1开始,它看起来是这样的:同样,Python成对地生成正常偏差,},如果没有额外的正常偏差存储,则存储的偏差值如果有可用的话。在
self.gauss_next
是{要找出
super().getstate()
返回的内容,您需要深入研究C source:它是一个长度为625的元组,包含624个构成梅森扭曲状态的单词,以及该单词集合中的当前位置。因此,该元组中的最后一个条目对应于NumPy状态的索引2处的值pos
。在下面是一个从Python状态转换为NumPy状态的示例,忽略高斯信息的细节:
^{pr2}$在从Python
Random
状态设置NumPyRandomState
状态之后,我们可以看到从两个rng生成的float是一致的:下面是反向转换:
如前所述,我们可以检查两台发电机的输出是否匹配:
Python和NumPy使用不同的算法来生成正态偏差(尽管这两种算法都成对地生成这些偏差),所以即使我们转移了高斯相关的状态,我们也不能期望生成的法向偏差能够匹配。但是,如果您只想在NumPy state对象中保存Python状态信息(反之亦然),以便从一个状态转换到另一个状态再转换回来不会丢失信息,那么这很容易做到:如果
has_gauss
在NumPy状态下为零,那么使用None
作为Python状态的最后一个条目,如果has_gauss
非零,则使用Python状态最后一个条目中NumPy状态的值cached_gaussian
。下面是一对实现这些转换的函数:相关问题 更多 >
编程相关推荐