我遇到了其中一次采访中提到的问题。
问题 - 想象一下,您将获得大量数据元素(5月份谷歌搜索查询,圣诞节期间在沃尔玛购买的产品,电话簿中的姓名,等等)。您的目标是有效地返回从原始流均匀分布的1,000个元素的随机样本。你会怎么做?
我正在寻找 -
这可能是一个模糊的问题..我试图谷歌“随机抽样数据集”但没有找到任何相关结果。
答案 0 :(得分:3)
二进制样本/不样本可能不是正确的答案..假设您想要抽样1000个字符串并且您通过硬币投掷来实现..这意味着大约在访问2000字符串之后......您将完成。那其余的字符串怎么样?
我看过这篇文章 - http://gregable.com/2007/10/reservoir-sampling.html
非常清楚地回答了这个问题。
让我把摘要放在这里 -
简单的解决方案
为您在流中看到的每个元素分配一个随机数,然后始终始终保留前1000个编号元素。
水库采样
创建一个包含1,000个元素的库(数组),并用流中的前1,000个元素填充它。 从i = 1,001开始。在第1001步之后的概率应该是元素1,001(或任何元素)在1,000个元素的集合中?答案很简单:1,000 / 1,001。因此,生成0到1之间的随机数,如果小于1,000 / 1,001,则应该使用元素1,001。 如果您选择添加它,则替换随机选择的储层中的任何元素(比如元素#2)。元素#2在步骤1000中肯定处于储层中,并且其被移除的概率是元素1,001被选择的概率乘以随机选择#2作为替换候选者的概率。该概率为1,000 / 1,001 * 1 / 1,000 = 1/1,001。因此,#2在这一轮中幸存的概率为1 - 即1,000或1,001。
这可以延续到第i轮 - 保持第i个元素的概率为1,000 / i,如果你选择保留它,则从储层中替换一个随机元素。该步骤之前的任何元素在储层中的概率是1,000 /(i-1)。它们被移除的概率是1,000 / i * 1 / 1,000 = 1 / i。每个元素在它们已经存在于储层中时附着的概率是(i-1)/ i,因此在i轮之后元素在储层中的总体概率是1,000 /(i-1)*(i- 1)/ i = 1,000 / i。
答案 1 :(得分:1)
我认为你已经松散地使用了无限这个词,采样的前提是每个元素都有相同的机会存在于样本中,这只有在你至少经历过每一个元素时才有可能。所以我将无限翻译成一个大数字,表示你需要一个通过解决方案而不是多次通过。
水库采样是一种可行的方法虽然来自@abipc的分析看起来正确,但并不完全正确。
如果我们首先明确我们想要什么,那就更容易了。想象一下,你有N个元素(N未知),你需要选择1000个元素。这意味着我们需要设置一个采样方案,其中样本中任何元素的概率恰好为1000 / N,因此每个元素具有相同的样本概率(基于其在原始位置上的位置不优先于任何元素)列表)。 @abipc提到的方案工作正常,概率计算如下 -
在第一步之后你有1001个元素,所以我们需要以概率1000/1001选择每个元素。我们选择具有该概率的第1001个元素,这样就可以了。现在我们还需要证明每个其他元素也具有相同的样本概率。
p(样本中剩余的任何其他元素)= [1 - p(该元素为 从样本中移除)]
= [ 1 - p(1001st element is selected) * p(the element is picked to be removed) = [ 1 - (1000/1001) * (1/1000)] = 1000/1001
很好,现在我们已经证明每个元素都有1000/1001的概率在样本中。这个精确的参数可以使用归纳法扩展到第i步。
答案 2 :(得分:1)
据我所知,这类算法称为储层采样算法。
我从DataMining知道其中一个,但不知道它的名称:
理论上可以证明,在这种流处理的任何步骤中,大小为S的存储包含具有相同概率的元素S / N_you_have_seen。
所以例如S = 10;
N_you_have_seen = 10 ^ 6
S - 是有限数; N_you_have_seen - 可以是无限数;