Python种子通过子函数

时间:2017-01-15 00:40:12

标签: python seed random-seed

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

当我在子函数中有种子时,main函数中的随机数也会从子函数中的种子中获得效果。并且,从主功能到子功能没有这样的效果。 例如,请考虑以下代码。

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),我会得到类似的结果。 愿有人向我解释发生了什么吗?

先谢谢, 阿夫欣

2 个答案:

答案 0 :(得分:1)

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

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。< / p>

尝试这样的事情:

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)

现在你的函数应该对外部代码使用随机数生成器没有影响。

答案 1 :(得分: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')