调用np.random.shuffle()后随机状态如何更新?受列表长度影响吗?
np.random.shuffle()的随机状态更新逻辑及列表长度的影响
嘿,咱们来拆解你问的这两个问题,结合你做的实验一步步分析:
核心结论先给你摆出来
1. 随机状态是怎么更新的?
np.random.shuffle()本质用的是Fisher-Yates洗牌算法,状态更新逻辑分两种情况:
- 如果待打乱的数组长度
n ≤ 1:根本不需要做任何交换操作,随机状态纹丝不动,完全没变化。 - 如果
n > 1:算法会从数组末尾往前遍历,对每个位置i(从n-1到1)生成一个0到i之间的随机整数,用来找要交换的位置。每生成一个随机数,就会推进随机数生成器的状态——对于默认的MT19937生成器来说,就是内部的索引指针往前走一步;当指针走到状态数组的末尾时,会重新生成整个状态数组,再重置指针。
2. 更新过程受列表长度影响吗?
肯定受影响!而且是直接相关:长度n越大,洗牌时需要生成的随机数就越多(总共要生成n-1个),随机状态推进的幅度就越大。
你的实验结果怎么看?
你做的实验很有意思,但有个小细节你没注意到:np.random.get_state()返回的是一个三元组(生成器类型, 状态数组, 索引指针),但你只打印了前两个部分的内容,漏掉了关键的索引指针!
看你的实验结果:
- 当数组长度为1时,状态和初始完全一致,这正好对应我们说的
n≤1时无更新的情况。 - 当长度≥8时,状态数组的前5个元素看起来一模一样,但实际上索引指针已经不一样了:比如长度8的洗牌要生成7个随机数,指针走7步;长度15的洗牌要生成14个随机数,指针走14步——这俩状态其实完全不同,只是状态数组还没到需要重新生成的地步,所以前5个元素没变化。
如果想完整验证,你可以修改代码,把索引指针也打印出来:
import numpy as np np.random.seed(3) state = np.random.get_state() print(f"{state[0]}, state array first 5: {state[1][:5]}, index: {state[2]}") delta = 7 for t in [3,7,8, 9, 10]: print('-'*20) x = np.power(2, t) np.random.seed(3) a = np.arange(x-delta) np.random.shuffle(a) state = np.random.get_state() print(f"{x-delta}: {state[0]}, state array first 5: {state[1][:5]}, index: {state[2]}") np.random.seed(3) a = np.arange(x) np.random.shuffle(a) state = np.random.get_state() print(f"{x}: {state[0]}, state array first 5: {state[1][:5]}, index: {state[2]}") np.random.seed(3) a = np.arange(x+delta) np.random.shuffle(a) state = np.random.get_state() print(f"{x+delta}: {state[0]}, state array first 5: {state[1][:5]}, index: {state[2]}")
跑这个代码你就能看到,不同长度的数组洗牌后,索引指针的数值完全不同,这就直接证明了随机状态的更新确实和列表长度挂钩。
内容的提问来源于stack exchange,提问作者user7586189
相关产品推荐
相关产品推荐

