水塘抽样【算法杂例】【C++实现】

目录

1.基本概念

(1)介绍

(2)算法步骤

(3)算法证明

2.算法实现

(1)数据结构

(2)抽样 


1.基本概念
(1)介绍

水塘抽样(Reservoir Sampling)是一种随机算法,用于从集合S中随机并等概率抽取k个元素(|S|可以是未知的,这尤其适用于不能把所有元素一次性加载到内存的情况)。

(2)算法步骤

首先从S中抽取前k个样本放入水塘reservior  

然后顺序遍历S,对每一个元素S[i](i>=k),都根据其下标i生成一个随机数randnum∈[0,i]。若randnum<k,就用S[i]替换水塘中已有的元素reservior[randnum]  

最后水塘里的所有元素即为最终抽样结果,且每个元素对应的概率均为k/|S|。

(3)算法证明

对每个S[i]:  

P(S[i]位于最终的水塘中)  

= P(S[i]替换掉水塘中某个元素) × P(S[i+1]没有替换掉水塘中的S[i]) × P(S[i+2]没有替换掉水塘中的S[i]) ×...× P(S[|S|-1]没有替换掉水塘中的S[i])  

= P(rand()%(i+1)<k) × P(rand()%(i+2)!=i) × P(rand()%(i+3)!=i) ×...× P(rand()%(|S|)!=i)  

= k/(i+1)×(1-1/(i+2))×(1-1/(i+3))×...×(1-1/|S|)  

= k/(i+1)×((i+1)/(i+2))×((i+2)/(i+3))×...×((|S|-1)/|S|)  

= k/|S|  

2.算法实现
(1)数据结构
#include <iostream>
#include <cstdlib>    // rand()

class ReserviorSampling{
public:
    static std::vector<int> sampling(std::vector<int>& S, int k);
};
(2)抽样 
static std::vector<int> ReserviorSampling::sampling(std::vector<int>& S, int k){
    std::vector<int> reservior(k); // 初始化水塘
    for(int i=0; i<k; i++){
        reservior[i] = S[i];
    }

    int i=k;
    for(auto &e:S){
        int randnum = rand()%(i+1);// 从i>=k开始,对每个i都随机获得一个[0~i]的整数
        if(randnum < k){
            reservior[randnum] = e;
        }
        i++;
    }

    return reservior;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值