Misra-Gries 算法

12/5/2017 3:39:22 PMpython

前言

Misra-Gries算法是頻繁項挖掘中一個著名的算法。頻繁項就是那些在數據流中出現頻率最高的數據項。頻繁項挖掘,這個看似簡單的任務倒是不少複雜算法的基礎,同時也有着普遍的應用。算法

對於頻繁項挖掘而言,一個簡單的想法是,爲全部的數據項分配計數器,當一個數據項到達,咱們即增長相應計數器的值。但當數據流的規模較大時,出於內存的限制,咱們每每不可能爲每一個數據項分配計數器。而Misra-Gries算法則是以一種清奇的思路解決了這個問題,實現了在內存受限的狀況下,以較小的錯誤率統計數據流中的頻繁項。數組

算法做者

Misra-Gries算法在1982年由華威大學的Misra和Gries提出。spa

頻繁項

咱們首先對頻繁項進行形式化的定義。code

給定一系列數據項,頻繁項挖掘的目的只是簡單地找到那些出現最頻繁的數據項。一般咱們定義這個問題爲找到那些出現頻率超過具體閾值的數據項。orm

定義1. 給定一個數據流\(S\),它包含\(n\)個數據項\(t\_1,\cdots,t\_n\),那麼一個數據項\(i\)的頻數爲\(f\_i=|\\{j|t\_j=i\\}|\)。而集合\(\\{i|f\_i>\phi n\\}\)中的元素,咱們稱爲\(\phi-\)頻繁項。blog

例子. 對於數據流\(S=(a,b,a,c,c,a,b,d)\),有\(f\_a=3,f\_b=2,f\_c=2,f\_d=1\)。若是設\(\phi=0.2\),那麼頻繁項有\(a,b\)\(c\)內存

Misra-Gries算法

即便\(\phi\)的值很大,解決這個問題的算法也至少要花費\(O(n)\)的空間。在這種狀況下,一個錯誤率爲\(\epsilon\)的近似算法被提出。這就是咱們的Misra-Gries算法。它的具體步驟以下:get

首先創建一個大小爲\(k\)的數組\(T\)it

對於數據流中依次到達的項\(i\)進行以下處理:若是項\(i\)在數組\(T\)中,則其對應的計數器\(c_i++\);若是項\(i\)不在數組\(T\)中,且數組\(T\)中的元素個數小於\(k-1\),則將項\(i\)加入數組\(T\),併爲其分配計數器\(c_i=1\);其餘狀況,將數組\(T\)中全部元素的計數器減1,此時若是數組\(T\)中存在元素的計數器值爲0,則從數組\(T\)移除這個元素。

當完成對數據流的掃描後,數據\(T\)中保存的\(k’(k’≤k-1)\)個元素便是數據流中的頻繁項。

Python實現

下面使用python3進行實現,其中數組\(T\)和計數器\(c_i\)使用字典實現。

def misra_gries(S,k):
    for i in S:
        if i in c:
            c[i]+=1
        elif len(c)<k-1:
            c[i]=1
        else:
            for j in list(c):
                c[j]-=1
                if c[j]==0:
                    c.pop(j)
        print (c)
    return list(c)

假設\(k=3,S=[1,2,1,4,2,1,5,2]\),那麼程序的輸出結果以下

{1: 1}
{1: 1, 2: 1}
{1: 2, 2: 1}
{1: 1}
{1: 1, 2: 1}
{1: 2, 2: 1}
{1: 1}
{1: 1, 2: 1}
[1, 2]
[Finished in 0.2s]

正確性證實

上面說到了這個算法是一個近似算法,這代表算法輸出的結果並不必定是頻繁項。Misra-Gries算法的錯誤率爲\(\epsilon\)

定義2. 給定一個包含\(n\)個數據項的數據流\(S\),上述的\(\epsilon-\)近似算法返回一個集合\(F\)。對於全部知足\(i\in F\)數據項\(i\),都有\(f\_i>(\phi-\epsilon)n\);而且不存在\(i \notin F\)的數據項\(i\),使得\(f\_i>\phi n\)

上面的定義代表,Misra-Gries算法輸出的數據項並不必定是頻繁項,可是頻繁項必定在輸出結果之中。後一句即是問題的關鍵了,它代表Misra-Gries算法能夠確保找到數據流中的頻繁項。下面咱們對這一點進行簡要的證實。

定理1. 計數器減一的操做最多執行了\(n/k\)輪。

證實:當數組\(T\)中元素的個數等於\(k-1\)時,纔會出現計數器減一的操做。此時,計數器值共減小\(k-1\),包括被捨棄的新數據項,計數器值之和共比實際到達的數據項的個數少\(k\)。因爲最後的計數器值之和是大於\(0\)的,且數據流中數據項的個數爲\(n\),因此計數器減一的操做最多執行了\(n/k\)輪。

定理2.\(k=\left\lceil\frac{1}{\phi}\right\rceil\),全部的\(\phi-\)頻繁項都會被Misra-Gries算法檢測出。

證實:由定理1可知,計數器減一的操做最多執行了\(n/k\)輪。所以,算法結束時,數據項\(i\)計數器的值\(c_i\),知足\(c_i\leq f_i\leq c_i+n/k\)。對於全部不在數組\(T\)中的數據項\(i\),有\(c_i=0\),因而\(f_i\leq n/k\leq \phi n\)。故全部知足\(f_j>\phi n\)的數據項\(j\),即全部的\(\phi-\)頻繁項都會被Misra-Gries算法檢測出。

參考

[1] Cormode G. Misra-Gries Summaries[M]. Springer US, 2014.
http://dimacs.rutgers.edu/~graham/pubs/papers/encalgs-mg.pdf

本文連接:www.superzhang.site/blog/misra-gries-algorithm

相關文章
相關標籤/搜索