以下代码导入了NumPy并设置了种子。
import numpy as np
np.random.seed(42)
然而,我不想设置随机种子,而是更关心如何读取它。random.get_state()
似乎并不包含种子。文档 中没有明显的答案。
如果我没有手动设置随机种子,如何检索由 numpy.random
使用的当前种子?
我想使用当前种子来在进程的下一次迭代中继续使用。
以下代码导入了NumPy并设置了种子。
import numpy as np
np.random.seed(42)
然而,我不想设置随机种子,而是更关心如何读取它。random.get_state()
似乎并不包含种子。文档 中没有明显的答案。
如果我没有手动设置随机种子,如何检索由 numpy.random
使用的当前种子?
我想使用当前种子来在进程的下一次迭代中继续使用。
简短的回答是你不能这样做(至少不是通常情况下)。
numpy使用的 Mersenne Twister 随机数生成器 (RNG) 有219937-1个可能的内部状态,而单个64位整数只有264个可能的值。因此,无法将每个RNG状态映射到唯一的整数种子。
你可以使用 np.random.get_state
和 np.random.set_state
直接获取和设置RNG的内部状态。 get_state的输出是一个元组,其第二个元素是一个 (624,)
的32位整数数组。这个数组的位数足以表示RNG的每个可能的内部状态 (2624 * 32 > 219937-1)。
get_state
返回的元组可以像种子一样用于创建可重复的随机数序列。例如:import numpy as np
# randomly initialize the RNG from some platform-dependent source of entropy
np.random.seed(None)
# get the initial state of the RNG
st0 = np.random.get_state()
# draw some random numbers
print(np.random.randint(0, 100, 10))
# [ 8 76 76 33 77 26 3 1 68 21]
# set the state back to what it was originally
np.random.set_state(st0)
# draw again
print(np.random.randint(0, 100, 10))
# [ 8 76 76 33 77 26 3 1 68 21]
get_state
的输出称为“种子”,那么我回答中展示的代码对你就有效。我理解OP的问题是“np.random.seed
的反函数是什么?”但出于我上面讨论过的原因,这是不可能的。 - ali_mRandomState
中的 seed
参数需要是介于0和2**32-1之间的整数或这些整数数组,因此@bukzor提出的问题并不重要。原则上,您可以通过解包本机Python整数中的位来生成uint32s数组,但这不是 RandomState
本身支持的功能。 - ali_m这篇文章旨在澄清ali_m的正确答案并更正Dong Justin的建议。
以下是我的研究发现:
np.random.seed(X)
设置随机种子后,您可以使用np.random.get_state()[1][0]
找到它。下面的代码段输出将向您展示为什么两个语句都是正确的。
语句1 - 您可以使用np.random.get_state()[1][0]
找到随机种子。
如果您使用np.random.seed(123)
设置了随机种子,则可以使用state=np.random.get_state()
以元组形式检索随机状态。以下是state
的详细信息(我在Spyder中使用变量资源管理器)。我正在使用屏幕截图,因为使用print(state)
会因为元组第二个元素中包含的数组大小而使控制台溢出。
您可以轻松地看到在第二个元素包含的数组中,123
是数组的第一个数字。使用seed = np.random.get_state()[1][0]
将给您123
。 完美吗?不完全是,因为:
语句2 - 然而,这对您来说几乎没有什么用处:
虽然一开始可能不会这样,但是您可以使用np.random.seed(123)
,使用seed = np.random.get_state()[1][0]
检索相同的数字,使用np.random.seed(444)
重置种子,然后(表面上)使用np.random.seed(seed)
将其设置回123
的情况。 但是,您在此之前已经知道了您的随机种子,因此不需要以这种方式进行操作。下一个代码部分还将显示,您不能使用np.random.get_state()[1][0]
获取任何随机状态的第一个数字并期望重新创建该确切情况。请注意,您可能需要完全关闭和重新启动内核(或调用np.random.seed(None)
)才能看到这一点。
以下代码段使用np.random.randint()
生成5个介于-10和10之间的随机整数,并存储有关该过程的一些信息:
代码段1
# 1. Imports
import pandas as pd
import numpy as np
# 2. set random seed
#seedSet = None
seedSet = 123
np.random.seed(seedSet)
# 3. describe random state
state = np.random.get_state()
state5 = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]
# 4. generate random numbers
random = np.random.randint(-10, 10, size = 5)
# 5. organize and present findings
df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)
注意到名为seedState
的列与state
下的第一个数字相同。我本可以将其作为独立的数字打印出来,但我想把它们放在同一个地方。另请注意,seedSet = 123
和np.random.seed(seedSet)
目前已被注释掉了。因为没有设置随机种子,所以你的数字会与我的不同。但重要的不是这个,而是你的结果内部一致性。 random seedSet seedState state
0 2 None 1558056443 1558056443
1 -1 None 1558056443 1808451632
2 4 None 1558056443 730968006
3 -4 None 1558056443 3568749506
4 -6 None 1558056443 3809593045
在这个特定的情况下,seed = np.random.get_state()[1][0]
等于1558056443
。按照Dong Justin回答的逻辑(以及我在编辑之前的回答),您可以使用np.random.seed(1558056443)
设置随机数种子并获得相同的随机状态。下面的代码片段将说明您不能: 代码片段2
# 1. Imports
import pandas as pd
import numpy as np
# 2. set random seed
#seedSet = None
seedSet = 1558056443
np.random.seed(seedSet)
# 3. describe random state
#state = np.random.get_state()
state = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]
# 4. generate random numbers
random = np.random.randint(-10, 10, size = 5)
# 5. organize and present findings
df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)
输出2:
random seedSet seedState state
0 8 1558056443 1558056443 1558056443
1 3 1558056443 1558056443 1391218083
2 7 1558056443 1558056443 2754892524
3 -8 1558056443 1558056443 1971852777
4 4 1558056443 1558056443 2881604748
看到区别了吗?np.random.get_state() [1] [0]
在输出1和输出2中是相同的,但其余的输出不同(最重要的是随机数不同)。因此,正如ali_m已经清楚地指出:
因此,将每个RNG状态映射到唯一整数种子是不可能的。
seedSet
应该是 None
,而 state5
应该是 state
。数据框的列顺序与输出不一致。文本中说“seed=123”已被注释掉……实际上没有,并且无论如何也没有使用。在片段2中,为了清晰起见,应该删除注释语句(语句 state = np.random.get_state()
不应该出现在代码中)。 - marsipannp.random.seed
设置的原始随机状态在生成数字后无法恢复,但是中间状态(_当前状态_)可以。 - OverLordGoldDragon了解随机种子的一个简单解决方案是随机生成一个,然后将其作为随机数生成器的种子。可以使用以下代码:
import numpy as np
seed = int(np.random.rand() * (2**32 - 1))
np.random.seed(seed)
请参考@vestland的回答;然而,它可能会误导:生成的数字之所以不同,并非由于无法映射状态,而是使用了不完整的编码:原始随机种子(通过
np.random.seed
设置)不能在生成数字后被恢复,但中间状态(当前状态)可以。
get_state()[1]
。完整的表示包括pos = get_state()[2]
。为了说明这一点:import numpy as np
state0 = np.random.get_state()
rand0 = np.random.randint(0, 10, 1)
state1 = np.random.get_state()
rand1 = np.random.randint(0, 10, 1)
assert all(s0 == s1 for s0, s1 in zip(state0[1], state1[1]))
我们生成了一个数字,但是 get_state()[1]
保持不变。然而:
np.random.set_state(state0)
assert np.random.randint(0, 10, 1) == rand0
对于state1
和rand1
同样如此。因此,@vestland的数字不同,因为当没有设置种子时,pos = 623
- 而如果我们使用np.random.seed
,pos = 624
。为什么存在这种不方便的差异?没有头绪。
总之,关于np.random.seed(s)
:
get_state()[1][0]
:检索精确重现状态的s
get_state()[1][0]
:可能会检索到s
,但它将无法重新创建当前状态(在get_state()
处)get_state()[1][0]
:将无法检索到s
。这是因为pos
耗尽了其表示。get_state()
:将精确地重新创建那个点。最后,行为也可能因get_state()[3:]
(当然还有[0]
)而有所不同。
检查np.random.get_state()
返回的数组的第一个元素,它看起来就像是随机种子。
np.random.get_state
和np.random.set_state
的组合,或者传递一个np.random.RandomState
实例来跟踪RNG的内部状态呢? - ali_mseed = np.random.randint(0, 100000)
设置一个种子? - Fangda Han