从一个大小未知的数组中检索 k 个随机数,我们使用一种称为蓄水池抽样的技术。 能否有人简要介绍一下如何使用示例代码?
从一个大小未知的数组中检索 k 个随机数,我们使用一种称为蓄水池抽样的技术。 能否有人简要介绍一下如何使用示例代码?
我其实不知道这个有一个名称,所以我从零开始证明并实现了它:
def random_subset(iterator, K):
result = []
N = 0
for item in iterator:
N += 1
if len(result) < K:
result.append(item)
else:
s = int(random.random() * N)
if s < K:
result[s] = item
return result
附近有证明。
accept it with probability s/k
部分在哪里?[引自http://blogs.msdn.com/spt/archive/2008/02/05/reservoir-sampling.aspx的算法] - LazerK/N
的概率接受事物,其中 N 是事物的当前计数。 - Larryimport random
def sample(iterable, n):
"""
Returns @param n random items from @param iterable.
"""
reservoir = []
for t, item in enumerate(iterable):
if t < n:
reservoir.append(item)
else:
m = random.randint(0, t)
if m < n:
reservoir[m] = item
return reservoir
randint
不是包含在内的吗? - user76284iterable
包含11个我们想要从中抽取n
=10的项目。对于第11个项目,t
将为10(因为enumerate
从0开始),我们生成一个介于0和10之间的随机整数(即11种可能性),使得将第11个项目添加到reservoir
的概率为n/t = 10/11。 - samJava
import java.util.Random;
public static void reservoir(String filename,String[] list)
{
File f = new File(filename);
BufferedReader b = new BufferedReader(new FileReader(f));
String l;
int c = 0, r;
Random g = new Random();
while((l = b.readLine()) != null)
{
if (c < list.length)
r = c++;
else
r = g.nextInt(++c);
if (r < list.length)
list[r] = l;
b.close();}
}
Python解决方案
import random
class RESERVOIR_SAMPLING():
def __init__(self, k=1000):
self.reservoir = []
self.k = k
self.nb_processed = 0
def add_to_reservoir(self, sample):
self.nb_processed +=1
if(self.k >= self.nb_processed):
self.reservoir.append(sample)
else:
#randint(a,b) gives a<=int<=b
j = random.randint(0,self.nb_processed-1)
if(j < k):
self.reservoir[j] = sample
k = 10
samples = [i for i in range(10)] * k
res = RESERVOIR_SAMPLING(k)
for sample in samples:
res.add_to_reservoir(sample)
print(res.reservoir)
out[1]: [9, 8, 4, 8, 3, 5, 1, 7, 0, 9]