python seed() 无法保持相同的序列
我在使用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 个回答
你只需要重新设置一下种子:
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),你会失去已经抽样的元素,这样就不行了。所以建议你使用列表,并在每次抽样之前重新设置种子。
你假设的 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
的工作方式却不是你想的那样!
看起来,random.sample
只有在种子和样本大小都保持不变的情况下,才是确定性的。换句话说,即使你重置了种子,如果生成的样本长度不同,这也不是“相同”的随机操作,可能会得到与使用相同种子生成较小样本时不同的初始子序列。也就是说,内部生成的随机数是相同的,但 sample
如何利用这些随机数来生成随机序列,取决于你请求的样本大小。
如果你从这个生成器中随机抽取独立样本,结果会正如你所期待的那样:
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, ...]