algo-水塘抽样

水塘抽样是一组随机算法,通过替换k个样本,从未知大小的n个总体中选择随机样本

简单但更慢的

初始化数组R(索引从到k),包含输入的前k个元素(也即包含 x 1 x_1 x1 x k x_k xk

那么对于新输入 x i ( i > k ) x_i(i>k) xi(i>k),生成从1到i之间的随机数j,若j属于1到k的区间内,那么设置R[j]= x i x_i xi

证明过程如下

  1. 初始化时,前k个元素都被选中了,那么选取概率都是1

  2. 在处理k之后的元素 x i x_i xi,以 k i \frac{k}{i} ik概率保留,那么在输入流(总数量n)完成之后保留的概率为
    P i = P ( 在 i 步被选中 ) × P ( 在 i + 1 不被替换 ) × . . . × P ( 在 n 不被替换 ) = k i × ( 1 − k j + 1 × 1 k ) . . . × ( 1 − k n × 1 k ) = k i × j j + 1 . . . × n − 1 n = k n P_i=P(在i步被选中)\times P(在i+1不被替换)\times...\times P(在n不被替换) \\ = \frac{k}{i}\times(1-\frac{k}{j+1}\times\frac{1}{k})...\times (1-\frac{k}{n}\times\frac{1}{k}) \\ = \frac{k}{i}\times \frac{j}{j+1}... \times \frac{n-1}{n} \\ = \frac{k}{n} Pi=P(i步被选中)×P(i+1不被替换)×...×P(n不被替换)=ik×(1j+1k×k1)...×(1nk×k1)=ik×j+1j...×nn1=nk

权重随机抽样

权重随机抽样设置最小堆,元素在最小堆中的值来自于随机数的 1 w e i g h t \frac{1}{weight} weight1次方,那么意味着权重越大,值也越大,也就有更大的机会被选中

type item struct {
	weight float64
}

func ReservoirSample(S []*item) {
	// 初始化最小堆
	h := &minPriorityQueue{}
	for _, i := range S {
		// r设置为正态分布随机数[0,1)的权重倒数次方,那么意味着权重越大r越大
		// 若r大于最小堆的最小值,那么便替换掉该最小值
		r := math.Pow(rand.NormFloat64(), 1/i.weight)
		if h.GetCount() < k {
			h.Insert(r, i)
		} else {
			if r > h.GetMin() {
				h.RemoveMin()
				h.Insert(r, i)
			}
		}
	}
}

Ref

  1. https://en.wikipedia.org/wiki/Reservoir_sampling

你可能感兴趣的:(algorithm,算法)