这是我正在使用的生成器:
from random import Random
def shuffle(size):
"""Yield random items from range(size) without replacement."""
pool = list(range(size))
rng = Random()
while pool:
yield pool.pop(rng.randrange(len(pool)))
当我使用这个发生器时,它似乎不那么随机。例如,前4个项目通常都以结果的第一个或第二个结束。
我正在考虑做出这样的改变:
def shuffle(size):
"""Yield random items from range(size) without replacement."""
pool = list(range(size))
rng = Random()
while pool:
i = rng.randrange(len(pool))
yield pool[i]
pool[i] = pool[-1]
del pool[-1]
这类似于random.sample(第326行)所做的事情。我不知道这是为了速度还是因为它在不牺牲速度的情况下使它更随机。
我更喜欢第一个简单的例子,但是第二个例子混合了更多,我不知道PRNG是否与真正的随机性相提并论。有没有办法证明第二个例子是否更随机,可能是通过引用Mersenne Twister算法(Python使用的)中的弱点?
如果无法以某种方式证明任何事情,我将如何测试两种算法的随机性?我知道我需要用很多试验来编写测试,但我不知道如何分析结果。
我不想使用random.sample
,因为我希望我的最终列表能够进行部分排序,而且我认为生成器更适合。
答案 0 :(得分:2)
假设您有一个list(range(10))
列表,并且您在追回号码5
时进行跟踪。
在随机场景中,如果算法运行了100次,则数字5
将作为第一个数字返回,与最后一个数字相同。因此,如果您按频率跟踪返回位置的地图,您希望看到类似的内容:
[{0: 10, 1: 11,
2: 8, 3: 12,
4: 10, 5: 10,
6: 9, 7: 10,
8: 10, 9: 10]
您可以使用类似Kolmogorov-Smirnov测试的方法来证明分布不同或相同。
答案 1 :(得分:2)
这是一个快速测试:
- Chi-square distribution
- Incomplete gamma function
- Kolmogorov-Smirnov test
如果您不熟悉所有这些数学概念,请不要使用RNG。你没有做什么来“混淆”Python的内置MT会让它变得更好,并且有数千种方法可以让它变得更糟。提供的工具非常好。保持简单,遵守规则。
答案 2 :(得分:0)
random.py
私有_randbelow()
是在从N种可能性中进行伪随机选择时提供一致性的原因。从randrange()
到shuffle()
的所有内容都构建了。如果没有用更好的基础PRNG取代Twister,你无法改进它。
sample()
被编码为速度,而不是"改善随机性"。来自"中间"列表(如您的第一个方法所做的那样)平均需要O(len(pool))
个时间,因此如果运行到耗尽,您的第一个方法需要size
中的二次方。从列表的右端弹出需要恒定的时间,因此如果运行到耗尽,则第二种方法具有更好的O(size)
渐近时间行为。 Python的sample()
根本不流行,因为它不是必要的费用来解决问题。
但请注意,除非列表很长,否则渐近线并不重要。例如,如果size
小于几百,您可能不会注意到两种方法之间的速度存在任何实际差异。但是,如果size
可以,例如,数百万。
我不知道"我不想使用random.sample
,因为我希望我的最终列表能够被部分排序"可能意味着。没有"最终列表"在您展示的任何内容中,任意方法随机选择元素而不进行替换将产生"部分排序"结果纯属偶然。
这是一种合理平易近人的方式来量化洗牌方法"似乎是随机的":
http://gregbee.ch/blog/determining-the-bias-of-a-shuffle-algorithm
该(或任何其他可行的方法)基于数千次试运行计算统计数据。