搞定演算法 蓄水池演算法

2021-09-24 23:27:32 字數 1384 閱讀 4984

取樣問題經常會被遇到,比如:

1、從 100000 份調查報告中抽取 1000 份進行統計;

2、從一本很厚的**簿中抽取 1000 人進行姓氏統計;

3、從 google 搜尋 "ken thompson",從中抽取 100 個結果檢視哪些是今年的。

既然說到取樣問題,最重要的就是做到公平,也就是保證每個元素被取樣到的概率是相同的。所以可以想到要想實現這樣的演算法,就需要擲骰子,也就是隨機數演算法。(這裡就不具體討論隨機數演算法了,假定我們有了一套很成熟的隨機數演算法了)

對於第乙個問題,還是比較簡單,通過演算法生成 [0,100000−1)[0,100000−1) 間的隨機數 1000 個,並且保證不重複即可。再取出對應的元素即可。

但是對於第二和第三個問題,就有些不同了,我們不知道資料的整體規模有多大。可能有人會想到,我可以先對資料進行一次遍歷,計算出資料的數量 n,然後再按照上述的方法進行取樣即可。這當然可以,但是並不好,畢竟這可能需要花上很多時間。也可以嘗試估算資料的規模,但是這樣得到的取樣資料分布可能並不平均。

終於要講到蓄水池取樣演算法(reservoir sampling)了。先說一下演算法的過程:

1、假設資料序列的規模為 n,需要取樣的數量的為 k。

2、首先構建乙個可容納 k 個元素的陣列,將序列的前 k 個元素放入陣列中。

3、然後從第 k+1 個元素開始,以 k/n 的概率來決定該元素最後是否被留在陣列中(每進來乙個新的元素,陣列中的每個舊元素被替換的概率是相同的)。 當遍歷完所有元素之後,陣列中剩下的元素即為所需採取的樣本。

第 1 種情況:對於陣列中第 i 個資料(i ≤ k)。在 k 步之前,被選中的概率為 1。當走到第 k+1 步時,被第 k+1 個資料替換的概率 = 第k+1個元素被選中的概率 * 第i個數 被選中替換的概率,即為

第 2 種情況:對於第 j 個資料(j > k)。第 j個資料被選中的概率為 k / j。不被第 j + 1 個元素替換的概率為

public class reservoirsampling 

// 初始化所有資料

int arr = new int[n];

for(int i = 0; i < n; i++)

int pool = new int[k];

for(int i = 0; i < k; i++)

random random = new random();

// k+1個元素開始進行概率抽樣

for(int i = k; i < n; i++)

}return pool;

}public static void main(string args)

}

蓄水池演算法

參考文章 問題定義 給你乙個長度為n的鍊錶。n很大,但你不知道n有多大。你的任務是從這n個元素中隨機取出k個元素。你只能遍歷這個鍊錶一次。你的演算法必須保證取出的元素恰好有k個,且它們是完全隨機的 出現概率均等 求解蓄水池抽樣演算法 該演算法是針對從乙個序列中隨機抽取不重複的k個數,保證每個數被抽取...

蓄水池演算法

適用情況 從n個數中等概率隨機取出k個數,n很大,k也很大 n不固定增量型 內容 當i屬於1 k i入池 當i k i以概率k i決定是否進入池,1 k概率剔除池中乙個數 證明 1 當i 當k個數時,i留下概率 1 當k 1個數時,i被淘汰的概率 1 k k k 1 1 k 1 i留下概率 1 1 ...

蓄水池演算法

在乙個未知的池子裡選1個數字,讓他們被選擇概率一致。假設n的時候,前n個數字被選擇的概率都是1n 當為n 1時候,當前n 1這個數,我們選擇的概率是1n 1,其餘數字的概率是nn 1,那麼一共有n個數字的概率是1n 所以 n 1n 1 n 1 1n 1 具體演算法 使用的方式是i random.ra...