python seed() 无法保持相同的序列

15 投票
4 回答
17219 浏览
提问于 2025-04-18 02:42

我在使用random.seed()这个函数,想要让random.sample()每次从列表中抽取的随机数保持一致。但是在我抽取更多值的时候,数字却发生了变化……我原以为seed()函数的作用就是让数字保持不变。

这里有个测试,我用来证明它并没有保持相同的数字。

import random

a=range(0,100)
random.seed(1)
a = random.sample(a,10)
print a

然后我把抽样的数量提高,结果序列就会改变(至少对我来说,总是这样):

a = random.sample(a,40)
print a

我算是个新手,所以可能这是个简单的解决办法,但我会很感激任何帮助。谢谢!

4 个回答

0

你只需要重新设置一下种子:

a = list(range(100))
random.seed(1)  # seed first time
random.sample(a, 10)
>> [17, 72, 97, 8, 32, 15, 63, 57, 60, 83]
random.seed(1)  # seed second time with same value
random.sample(a, 40)
>> [17, 72, 97, 8, 32, 15, 63, 57, 60, 83, 48, 26, 12, 62, 3, 49, 55, 77, 0, 92, 34, 29, 75, 13, 40, 85, 2, 74, 69, 1, 89, 27, 54, 98, 28, 56, 93, 35, 14, 22]

但是在你的情况下,你用的是生成器,而不是列表。所以在第一次抽样后,a 的大小会变小(从100变成90),你会失去已经抽样的元素,这样就不行了。所以建议你使用列表,并在每次抽样之前重新设置种子。

4

你假设的 random.sample 的实现大概是这样的:

def samples(lst, k):
    n = len(lst)
    indices = []
    while len(indices) < k:
        index = random.randrange(n)
        if index not in indices:
            indices.append(index)
    return [lst[i] for i in indices]

这样的话,结果会是:

>>> random.seed(1)
>>> samples(list(range(20)), 5)
[4, 18, 2, 8, 3]
>>> random.seed(1)
>>> samples(list(range(20)), 10)
[4, 18, 2, 8, 3, 15, 14, 12, 6, 0]

不过,实际上 random.sample 的实现并不是这样;seed 的确是按照你想的那样工作的,但 sample 的工作方式却不是你想的那样!

4

看起来,random.sample 只有在种子和样本大小都保持不变的情况下,才是确定性的。换句话说,即使你重置了种子,如果生成的样本长度不同,这也不是“相同”的随机操作,可能会得到与使用相同种子生成较小样本时不同的初始子序列。也就是说,内部生成的随机数是相同的,但 sample 如何利用这些随机数来生成随机序列,取决于你请求的样本大小。

10

如果你从这个生成器中随机抽取独立样本,结果会正如你所期待的那样:

In [1]: import random

In [2]: random.seed(1)

In [3]: [random.randint(0, 99) for _ in range(10)]
Out[3]: [13, 84, 76, 25, 49, 44, 65, 78, 9, 2]

In [4]: random.seed(1)

In [5]: [random.randint(0, 99) for _ in range(40)]
Out[5]: [13, 84, 76, 25, 49, 44, 65, 78, 9, 2, 83, 43 ...]

正如你所看到的,前十个数字确实是相同的。

问题在于,random.sample() 是在进行 不放回抽样,这就造成了一些干扰。要理解这些算法是如何工作的,可以参考一下 水库抽样。简单来说,后面抽取的样本可能会把前面抽取的样本挤出结果集。

一种替代方法是先打乱一个索引列表,然后取前面10个或40个元素:

In [1]: import random

In [2]: a = range(0,100)

In [3]: random.shuffle(a)

In [4]: a[:10]
Out[4]: [48, 27, 28, 4, 67, 76, 98, 68, 35, 80]

In [5]: a[:40]
Out[5]: [48, 27, 28, 4, 67, 76, 98, 68, 35, 80, ...]

撰写回答