fromrandomimportRandomdefRandomSelect(rand=None):selection=Nonecount=0ifrandisNone:rand=Random()whileTrue:# Outputs the current selection and gets next itemitem=yieldselectionifrand.randint(0,count)==0:selection=itemcount+=1
下面这段程序示意了如何调用 RandomSelect 函数来测验其随机效果:
python
1
2
3
4
5
6
7
8
9
10
11
12
13
# Sample code to use RandomSelect functionn=10repeat=100000occurrences=[0foriinxrange(n)]rand=Random()foriinxrange(repeat):selector=RandomSelect(rand)selector.next()selection=Noneforiteminxrange(n):selection=selector.send(item)occurrences[selection]+=1printoccurrences
看一下概率,如果最终被选取的是第 i 个元素(1 <= i <=
n),那就必须是遍历到它的时候,恰好被选中(random.randint(0, i - 1) == 0 或者 Random.Next(i) == 0),并且从此之后都恰好再也没有被其他元素替换掉。这些事件彼此独立,计算概率的方法正好是上面提到的式子,最终的概率就是 1/n。
OK,问题解决了。结束之前再做个简单的扩展,改成等概率随机选取 m 个元素(可知每个元素被选中的概率都是 m/n)。
解决办法也非常简单,只要在上面的代码中,把 selectedItem(selection)改成一个长度为 m 的数组,稍作调整就可以了。
这里就给出 Python 的程序片段:
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fromrandomimportRandomdefRandomSample(m=1,rand=None):selection=[]count=0ifrandisNone:rand=Random()whileTrue:# Outputs the current selection and gets next itemitem=yieldselectioniflen(selection)<m:selection.append(item)else:idx=rand.randint(0,count)ifidx<m:selection[idx]=itemcount+=1