基數估計演算法(一):Flajolet-Martin演算法
簡介
說起基數估計演算法的始祖,或許就是由Flajolet和Martin大佬發表的論文《 Probabilistic counting algorithms for data base applications 》開始的吧。他們提出在大資料中基於概率來估計基數的演算法,江湖人稱 FM-sketch演算法。
基礎版
首先定義一個hash函式:
function hash(x): ->
再定義bit函式:
bit(y, k) 表示 y的二進位制表示第k個bit數值(0或1).
即
定義tail(y)表示y的二進位制表示中末尾出現第一個1的位置(從0開始計數),即連續0的個數:
定義BITMAP[0…L-1]陣列,BITMAP[i] 表示在可重複集合M中有一個數經過hash後呈現
具體BITMAP的計算如下:
for i :=0 to L- 1 do BITMAP[i] :=O;
for all x in M do
begin
index := tail(hash(x));
if BITMAP[index] = 0 then BITMAP[index] := 1;
end;
好了定義了這麼多,重點來了!
如果M中的基數為n,按照概率,BITMAP[0]大約有
可以得出結論,當
設BITMAP裡最左邊的0的位置為R,因此我們可以用R來近似
比如一個24bits(L=24)的BITMAP如下:
111111111111001100000000
則左邊的0出現的位置為12,即R=12.
在確保hash值是均勻分佈的條件下,R的數學期望值為:
可以證明R的方差為:
標準版
很明顯,在上述介紹的方法中,估計值很不精確。
因此實際中,為了減小誤差提高精度,通常會採用多組hash方法。
具體可以利用m組不同的hash方法,生成m個BITMAP,然後對每個BITMAP採用同樣的方法計算出對應的R值,然後求平均。
有:
更進一步,還可以設計A組hash函式,其中每組B個hash函式,這些hash函式各不相同且對映結果均勻分佈。然後利用每組中的B個雜湊函式計算出B個估計值,求出B個估計值的算術平均數作為該組的估計值;最後將所有組的結果進行排序,取中位數作為最終的輸出結果。
顯然這種做法精度會進一步提高。
但是,這種做法卻有些缺點。首先要設計這麼多個不同且hash結果分佈均勻的hash函式是困難的,其次這麼做顯然既耗時也耗空間。
顯然F和M兩位大佬看出了這個問題,所以他們採用的還是用一個hash函式來處理,不同的是BITMAP卻是有m組。具體做法是,當一個數y進行hash之後,首先mod m,即
所以理想狀態下均勻分佈,則m個組中每個組都有
得出結論
虛擬碼,如下:
Probabilistic counting with stochastic averaging (PCSA)
m取不同值時的結果如下:
TIPs
BITMAP長度L的取值
經證明,L>log2(nm)+4 . 結果較理想。
具體地,當m=64時,若L=16,可以計算的基數達 n ~105 ;若L=24,基數可以超過107 .BITMAP數量m的取值(即多少組)
經證明,該演算法的標準誤差為:0.78m√ .
因此其與m−−√ 成反比。具體的,當m=64時,標準誤差大約為10%;當m=256時,標準誤差將減小到5%。演算法可應用於分散式計算
論文中有闡述,這裡就不多作介紹。
參考資料
- P. Flajolet and G. Nigel Martin. Probabilistic counting algorithms for data base applications. Journal of computer and system sciences, 31(2):182–209, 1985.