如何保留数据流的随机子集?

时间:2010-12-02 21:55:39

标签: algorithm sampling

我有一系列事件流经我的服务器。我不可能存储所有这些,但我希望能够定期处理其中的一些。所以,我想保留一个流的子集,它是我所见过的所有内容的随机抽样,但是上限为最大尺寸。

所以,对于每个新项目,我需要一个算法来决定是否应该将它添加到存储的集合,或者我是否应该丢弃它。如果我添加它,并且我已经达到极限,我需要一个算法来驱逐其中一个旧项目。

显然,只要我低于我的极限(只保存一切),这很容易。但是,一旦我超过这个限制,我怎样才能保持良好的随机抽样而不偏向旧物品或新物品?

谢谢,

6 个答案:

答案 0 :(得分:6)

这是一个常见的面试问题。

一种简单的方法是以概率k / n(或1,以较小者为准)保存第n个元素。如果您需要删除元素以保存新样本,请逐出随机元素。

这为您提供了n个元素的均匀随机子集。如果你不知道n,你可以估计它并得到一个近似统一的子集。

答案 1 :(得分:5)

这称为随机抽样。资料来源:http://en.wikipedia.org/wiki/Reservoir_sampling

array R[k];    // result
integer i, j;

// fill the reservoir array
for each i in 1 to k do
    R[i] := S[i]
done;

// replace elements with gradually decreasing probability
for each i in k+1 to length(S) do
    j := random(1, i);   // important: inclusive range
    if j <= k then
        R[j] := S[i]
    fi
done

一个不错的解释/证据:http://propersubset.com/2010/04/choosing-random-elements.html

答案 2 :(得分:1)

虽然this paper并不是您正在寻找的,但它可能是您搜索的良好起点。

答案 3 :(得分:1)

将样本存储在先进先出(FIFO)队列中。

设置样本之间如此多事件的采样率,或者将其随机化一点 - 取决于您的事件模式。

保存每个第n个事件,或者在您的费率告诉您的时间,然后将其粘贴到队列的末尾。

如果尺寸太大,

从顶部弹出一个。

答案 4 :(得分:0)

指定记录每个事件的概率,并将事件存储在可索引的数据结构中。当结构的大小达到阈值时,删除随机元素并添加新元素。在Ruby中,你可以这样做:

@storage = []
prob = 0.002

while ( message = getnextMessage) do
    @storage.delete((rand() * @storage.length).floor) if @storage.length > MAX_LEN
    @storage << message if (rand() < prob) 
end

这可以解决您的最大尺寸和您对事件发生时的非偏见。您还可以通过将存储的元素分区为存储桶,然后从具有多个元素的任何存储桶中删除元素来选择删除哪个元素。例如,桶方法允许您从每小时保留一个。

您还应该知道抽样理论是大数学。如果您需要的不仅仅是外行人的想法,您应该咨询您所在地区的合格数学家。

答案 5 :(得分:0)

这假设您不知道将接收的事件总数,并且您不需要子集中的最少元素数。

arr = arr[MAX_SIZE] //Create a new array that will store the events. Assuming first index 1.
counter = 1 //Initialize a counter.

while(receiving event){
  random = //Generate a random number between 1 and counter
  if( counter == random ){
     if( counter <= MAX_SIZE ){
        arr[counter] = event
     }
     else{
        tmpRandom = //Generate a random number between 1 and MAX_SIZE
        arr[tmpRandom] = event
     }
  }
  counter =+ 1

}