【算法】未知长度序列等概率采样

来源:互联网 发布:mac dock栏透明 编辑:程序博客网 时间:2024/05/16 09:15

问题是这样的,给一个序列,长度未知,要求从中随机等概率采样出m个元素。

最直观的解法是首先遍历序列,得到序列长度n,然后以m/n的概率从中随机取出m个元素。先不论从长度为n的序列中如何高效率的随机取出m个非重复元素,但是第一步遍历序列就使得算法时间复杂度为O(N2),空间复杂度为O(N)。在N非常大的情况下,此种解法几乎是不可能的。

N非常大的情况对应着下面的场景:服务器持续生成着日志数据,现在需要从这些日志流中等概率选取m条数据进行分析。此情况下,上面先求序列长度的解法已不再适用(日志数据持续产生,序列长度理论上是无限的)。此时,问题转化为:对于当前生成的一条数据,以某种机制决定是否保存这条数据,使得数据被采样到的概率相等。

假设某个时间节点下已产生的序列长度为n,按以下采样策略:
- 若n<=m,则之前的数据需全部保留,此时数据被采样的概率均等(都为1);
- 若n>m,则以m/n的概率保留最新元素,并从已有长度为m的结果序列中随即取出一个元素与之交换,此时结果序列中的每个元素被采样到的概率都应该是m/n,证明如下:
- n=m+1时,原结果序列下元素保留下来的概率为mm+1(11m)+(1mm+1)=mm+1,即mn;
- n=m+2时,原结果序列下元素保留下来的概率为mm+1(mm+2(11m)+(1mm+2))=mm+2,即mn
- n=m+k时,原结果序列下元素保留下来的概率为mm+k1(mm+k(11m)+(1mm+k))=mm+k,即mn

因此,按以上策略采样,能够保证元素在任意时间节点下的采样概率均等,且为mn。算法时间复杂度为O(N)

Python代码

# !/usr/bin/env python # -*- coding:utf-8 -*- # Author: NeoMT<matengneo@gmail.com>import random# 输入sequence长度未知,m为需要采样的数据个数def random_pick(m, sequence):  result = []  i = 0  while True:    try:      current_num = sequence[i]      if i < m:        result.append(current_num)      else:        j = random.randint(0, i)        if j < m:          result[j] = current_num      i = i + 1    except IndexError:      print "End of Sequence, Sequence num:", i      return resultif __name__ == '__main__':  sequence = [x for x in range(0, 11)]  print random_pick(10, sequence)
0 0
原创粉丝点击