我有一系列事件流经我的服务器。我不可能存储所有这些,但我希望能够定期处理其中的一些。所以,我想保留一个流的子集,它是我所见过的所有内容的随机抽样,但是上限为最大尺寸。
所以,对于每个新项目,我需要一个算法来决定是否应该将它添加到存储的集合,或者我是否应该丢弃它。如果我添加它,并且我已经达到极限,我需要一个算法来驱逐其中一个旧项目。
显然,只要我低于我的极限(只保存一切),这很容易。但是,一旦我超过这个限制,我怎样才能保持良好的随机抽样而不偏向旧物品或新物品?
谢谢,
答案 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
}