【问题标题】:Python seed through the subfunction通过子函数的 Python 种子
【发布时间】:2017-05-30 02:57:38
【问题描述】:

我有一个函数和一个子函数,并且在每个函数中都生成了一些随机数组。为了使结果可重现,我使用种子。但是我看到了奇怪的情况。

当我在子函数中有一个种子时,主函数中的随机数也会受到子函数中的种子的影响。而且,从主功能到子功能没有这样的效果。 例如,考虑以下代码。

import random
from random import randint
import numpy as np


def randgene():

    a=np.random.randint(0,5,size=5)
    print "a in function", a
    np.random.seed(seed=15)
    b=np.random.randint(0,5,size=5)
    print "b in function", b

    d=np.random.choice(50, size=5, replace = False)
    print "d in function", d
    # np.random.seed(seed=None)

def main():

    print "d-without seed", np.random.choice(50, size=5, replace = False)
    print "a-without seed", np.random.randint(0,5,size=5)
    print "b-without seed", np.random.randint(0,5,size=5)
    f = randgene()    
    print "d-without seed", np.random.choice(50, size=5, replace = False)
    print "a-without seed", np.random.randint(0,5,size=5)
    print "b-without seed", np.random.randint(0,5,size=5)
    f = randgene()
    print "d-without seed", np.random.choice(50, size=5, replace = False)
    print "a-without seed", np.random.randint(0,5,size=5)
    print "b-without seed", np.random.randint(0,5,size=5)

    np.random.seed(seed=10)

    print "d-with seed", np.random.choice(50, size=5, replace = False)
    print "a-with seed", np.random.randint(0,5,size=5)
    print "b-with seed", np.random.randint(0,5,size=5)

    f = randgene()

    print "d-with seed", np.random.choice(50, size=5, replace = False)
    print "a-with seed", np.random.randint(0,5,size=5)

    f = randgene()

    print "d-with seed", np.random.choice(50, size=5, replace = False)
    print "a-with seed", np.random.randint(0,5,size=5)

if __name__ == '__main__':
    main()

对于这段代码,我得到了这个结果:

d-without seed [14 29  9 42 18]
a-without seed [3 0 0 3 4]
b-without seed [3 2 0 2 1]
a in function [2 3 1 2 3]
b in function [0 4 0 4 3]
d in function [41 16 22 24 14]
d-without seed [ 8 21 32 39 11]
a-without seed [3 0 3 3 0]
b-without seed [1 2 2 1 4]
a in function [4 4 0 2 2]
b in function [0 4 0 4 3]
d in function [41 16 22 24 14]
d-without seed [ 8 21 32 39 11]
a-without seed [3 0 3 3 0]
b-without seed [1 2 2 1 4]
d-with seed [37 23 44 42 47]
a-with seed [2 0 0 4 4]
b-with seed [0 0 2 4 2]
a in function [0 0 2 3 0]
b in function [0 4 0 4 3]
d in function [41 16 22 24 14]
d-with seed [ 8 21 32 39 11]
a-with seed [3 0 3 3 0]
a in function [1 2 2 1 4]
b in function [0 4 0 4 3]
d in function [41 16 22 24 14]
d-with seed [ 8 21 32 39 11]
a-with seed [3 0 3 3 0]

每当我调用子函数时,您都会看到 d-with seed [ 8 21 32 39 11], a-with seed [3 0 3 3 0] 在主函数中重复出现。 但是,如果我在子函数中注释 np.random.seed(seed=15) 行,我会得到以下结果:

d-without seed [17 20 23 36 28]
a-without seed [3 1 1 2 0]
b-without seed [3 2 1 1 3]
a in function [1 2 2 0 4]
b in function [4 4 0 4 2]
d in function [ 9 46 19  7 47]
d-without seed [39 42 10 17  4]
a-without seed [2 3 0 2 4]
b-without seed [1 4 1 3 2]
a in function [1 1 3 3 2]
b in function [1 3 4 4 3]
d in function [ 0  2 45  5 19]
d-without seed [24 20 47  3 29]
a-without seed [3 0 3 3 3]
b-without seed [1 0 0 2 3]
d-with seed [37 23 44 42 47]
a-with seed [2 0 0 4 4]
b-with seed [0 0 2 4 2]
a in function [0 0 2 3 0]
b in function [4 4 0 1 1]
d in function [ 6 11 35  4  7]
d-with seed [19 47 43 38 15]
a-with seed [0 4 2 1 2]
a in function [1 2 1 3 2]
b in function [3 4 4 0 2]
d in function [38 31 17 43  2]
d-with seed [ 7 15 39  2 49]
a-with seed [3 4 1 4 0]

显然没有重复。因此,主函数中的种子对子函数没有影响。 如果我保留 np.random.seed(seed=15)np.random.seed(seed=None) 未注释,我会得到类似的结果。 有人可以解释一下发生了什么吗?

提前致谢, 阿夫辛

【问题讨论】:

  • 种子影响所有生成的随机数之后它被设置,无论在哪里。
  • @DYZ 谢谢,我明白了。

标签: python seed random-seed


【解决方案1】:

对于局部随机状态,只需使用numpy.random.RandomState 而不是numpy.random.seed 设置的全局状态。

一个例子:

import numpy as np

seed1 = 1
seed2 = 42

rs1 = np.random.RandomState(seed1)
rs2 = np.random.RandomState(seed2)
rs3 = np.random.RandomState(seed1)  # same seed value used for rs1

a = rs1.randint(0, 5, size=5)
b = rs1.randint(0, 5, size=5)

c = rs2.randint(0, 5, size=5)

e = rs3.randint(0, 5, size=5)
f = rs3.randint(0, 5, size=5)


eq = np.testing.assert_array_equal

try:
    eq(a, b, err_msg='OK, a should be != b')
except AssertionError:
    pass

try:
    eq(a, c, err_msg='OK, a should be != c')
except AssertionError:
    pass

eq(a, e, err_msg='ERROR')  # a and e are equal due to same seed
eq(b, f, err_msg='ERROR')  # b and f are equal due to same seed

print('OK')

【讨论】:

    【解决方案2】:

    随机数生成器种子用于设置其全局状态。该状态用于该点之后生成的所有数字(并且每个生成的数字都会导致状态发生更改)。您可以使用全局变量将您的示例与此示例进行比较:

    def print_and_increment(): # this is like generating a random number
        global x
        print("x was {}. Incrementing...".format(x))
        x += 1
        print("x is now", x)
    
    def func():
        global x
        print("func before seed")
        print_and_increment()
    
        x = 10 # this is equivalent to calling seed()
    
        print("func after seed")
        print_and_increment()
    
    x = 0  # seed
    print("top")
    print_and_increment()
    
    func()
    
    print("middle")
    print_and_increment()
    
    func()
    
    print("bottom")
    print_and_increment()
    

    如果您希望您的函数拥有自己始终使用的种子,但不改变外部使用的随机数生成器的状态,您可以使用numpy.random.get_statenumpy.random.set_state

    试试这样的:

    def randgene():
    
        prev_state = np.random.get_state()
    
        a=np.random.randint(0,5,size=5)
        print "a in function", a
        np.random.seed(seed=15)
        b=np.random.randint(0,5,size=5)
        print "b in function", b
    
        d=np.random.choice(50, size=5, replace = False)
        print "d in function", d
        # np.random.seed(seed=None)
    
        np.random.set_state(prev_state)
    

    现在您的函数应该不会影响外部代码对随机数生成器的使用。

    【讨论】:

      猜你喜欢
      • 2021-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-06
      • 2021-09-14
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      相关资源
      最近更新 更多