水塘抽樣(Reservoir sampling)

2021-10-02 03:19:22 字數 1564 閱讀 8759

水塘抽樣(reservoir sampling)

題目:給出乙個資料流,這個資料流的長度很大或者未知。並且對該資料流中的資料只能訪問一次。請寫出乙個隨機選擇演算法,使得資料流中所有資料被選中的概率相等。

這個問題的擴充套件就是:如何從未知或者很大樣本空間隨機的取k個數?或者說,資料流長度為n行,要隨機抽取k行,則每一行被抽取的概率為k/n。

這個問題也就是在大資料流中的隨機抽樣問題:當記憶體無法載入全部資料時,如何從包含未知大小的資料流中隨機選取k個資料,並且要保證每個資料被抽取到的概率相等。

當k =1

k=1k=

1時首先考慮最簡單的情況,當k=1

k=1k=

1時,如何選取:

通過以上規律可以看出,對於k=1

k=1k=

1的情況,資料流中第i個數被保留的概率為1

i\frac

i1​。只要採取這種策略,只需要遍歷一遍資料流就可以得到取樣值,並且保證所有資料被選中的概率均為1

n\frac

n1​。

當k

>

1k>1

k>1時

對於k

>

1k>1

k>

1的情況,我們可以採取類似的策略:

對於前k個數,全部保留,對於第i(i>k)個數,以k

i\frac

ik​的概率保留第i個數,並以1

k\frac

k1​的概率與前面已選擇的k個數中的任意乙個替換。

總結也就是說,在取第i個資料的時候,生成乙個01的隨機數p,如果p

p<\frac

p​,替換池中任意乙個為第i個數;當p

>ki

p>\frac

p>ik

​,繼續保留前面的數。直到資料流結束,返回此k個數。但是為了保證計算準確性,一般是生成乙個0i的隨機數,跟k相比。

scala**實現

import scala.util.random

/** * @author xiaoer

* @date 2020/1/11 23:53

*/object reservoirsampling

/*** 水塘抽樣演算法

** @param k 抽樣結果

* @param s 樣本總數

* @return k 樣本結果

*/def reservoirsampling(k: array[int], s: array[int]): array[int] =

// k+1 往後的資料

for (i <- k.length until s.length)

}// 返回值k}

}

Shuffle an Array 水塘抽樣

隨機性問題 水塘抽樣演算法可保證每個樣本被抽到的概率相等 使用場景 從包含n個專案的集合s中選取k個樣本,其中n為一很大或未知的數量,尤其適用於不能把所有n個專案都存放到主記憶體的情況 拿起第i張牌時,只從它前面的牌隨機選出j,或從它後面的牌隨機選出j交換即可 1 class solution 67...

水塘抽樣演算法

作用 水塘抽樣演算法是一種抽樣演算法,對於乙個很大的集合,抽取的樣本值能夠保證隨機.特點 其複雜度並不很高o n 並且能夠很大程度地節省記憶體.很多大公司的面試題都考察過這個演算法,以谷歌為例,有一道關於水塘抽樣的例題 我有乙個長度為n的鍊錶,n的值非常大,我不清楚n的確切值.我怎樣能寫乙個盡可能高...

leetcode 隨機概率 水塘抽樣

definition for singly linked list.struct listnode 水塘抽樣 維護乙個大小為1的水塘,由於確定head一定存在,定義res返回head val的值,然後讓head指向下乙個節點,同時定義乙個變數i,i初始化為2,當cur不為空的時候,迴圈在 0,i 1...