用FP-growth算法發(fā)現(xiàn)頻繁項集(一)

概述

  • 優(yōu)點:一般要快于Apriori
  • 缺點:實現(xiàn)比較困難斩个,在某些數(shù)據(jù)集上性能會下降
  • 適用數(shù)據(jù)類型:標稱型數(shù)據(jù)

FP-growth算法將數(shù)據(jù)存儲在一種稱為FP樹的緊湊數(shù)據(jù)結構中皮迟。FP代表頻繁模式(Frequent Pattern)办铡。

FP樹與其他樹結構類似。但它會把相似元素連接起來荣恐,被連起來的元素項可以看作是鏈表啤贩。如下圖所示。


圖1 一棵FP樹

一個元素項可以在一棵FP樹出現(xiàn)多次嘹吨。

FP樹會存儲項集的出現(xiàn)頻率,而每個項集會以路徑的方式存儲在樹中黍聂。

相似項之間的鏈接即節(jié)點鏈接(node link)躺苦,用于快速發(fā)現(xiàn)相似項的位置。

下面再簡單說明一下产还。

事務ID 事務中的元素項 最小支持度過濾后
001 r,z,h,j,p r,z
002 z,y,x,w,v,u,t,s z,y,x,t,s
003 z z
004 r,x,n,o,s r,x,s
005 y,r,x,z,q,t,p y,r,x,z,t
006 y,z,x,e,q,s,t,m y,z,x,s,t

上表是生成上面FP樹的數(shù)據(jù)匹厘。第二列“事務中的元素項”是原數(shù)據(jù),然后經(jīng)過最小支持度(關于支持度可以看之前Apriori算法的文章)過濾后脐区,留下頻繁項集愈诚。

圖1樹中節(jié)點z:5說明元素項出現(xiàn)5次。從z:5出發(fā),沿著路徑x:3炕柔、y:3酌泰,說明{z,x,y}出現(xiàn)3次。z:5 -> r:1說明{z,r}出現(xiàn)1次匕累。到這里兩條路徑陵刹,z一共被使用4次,所以剩下的一次就是它自身{z}欢嘿。通過觀察上表最后一列“最小支持度過濾后”衰琐,可以知道上述結論的正確性。以此類推炼蹦,就能大概知道FP樹和頻繁項集的對應關系了羡宙。

構建FP樹

FP樹的數(shù)據(jù)結構

因為FP樹比較復雜,所以定義一個類來保存節(jié)點信息掐隐。

class treeNode:
    def __init__(self, name, count, parentNode):
        self.name = name                 # 節(jié)點名字
        self.count = count               # 計數(shù)值
        self.nodeLink = None             # 用于鏈接相似元素項
        self.parent = parentNode
        self.children = {} 
    
    def inc(self, numOccur):
        self.count += numOccur
        
    # 將樹以文本形式顯示
    def disp(self, ind=1):
        print('  '*ind, self.name, ' ', self.count)
        for child in self.children.values():
            child.disp(ind+1)

測試一下狗热。


開始構建

除了FP樹外,還需要一個頭指針表來指向給定類型的第一個實例虑省。利用頭指針表可以快速訪問FP樹中一個給定類型的所有元素匿刮。如下圖。


圖2 帶頭指針表的FP樹

集合是無序的慷妙,假設有{z,x,y}{y,z,x}僻焚,那么在FP樹中只會表示一條路徑允悦。為了解決這個問題膝擂,在將集合添加到樹前,先基于元素項的出現(xiàn)頻率進行排序隙弛。如下表架馋。

事務ID 事務中的元素項 最小支持度過濾后 排序后
001 r,z,h,j,p r,z z,r
002 z,y,x,w,v,u,t,s z,y,x,t,s z,x,y,s,t
003 z z z
004 r,x,n,o,s r,x,s x,s,r
005 y,r,x,z,q,t,p y,r,x,z,t z,x,y,r,t
006 y,z,x,e,q,s,t,m y,z,x,s,t z,x,y,s,t

進行過濾和排序之后,就可以構建FP樹了全闷。從空集開始叉寂,不斷添加頻繁項集。如下圖总珠。


圖3 FP樹構建過程示意圖

大致了解FP樹構建過程后屏鳍,接下來就是代碼實現(xiàn)了。

def createTree(dataSet, minSup=1):
    headerTable = {}
    # 第一次遍歷數(shù)據(jù)集局服,統(tǒng)計每個元素項出現(xiàn)的次數(shù)
    for trans in dataSet:
        for item in trans:
            headerTable[item] = headerTable.get(item, 0) + dataSet[trans]
    # 移除不滿足最小支持度的項
    for k in list(headerTable.keys()):
        if headerTable[k] < minSup: 
            del(headerTable[k])
    freqItemSet = set(headerTable.keys())
    print('freqItemSet: ',freqItemSet)
    # 沒有滿足最小支持度的項钓瞭,則退出
    if len(freqItemSet) == 0: 
        return None, None
    # 擴展頭指針表以便后面的鏈接
    for k in headerTable:
        headerTable[k] = [headerTable[k], None] 
    print('headerTable: ',headerTable)
    # 創(chuàng)建樹
    retTree = treeNode('根節(jié)點', 0, None)
    for tranSet, count in dataSet.items():     # 第二次遍歷數(shù)據(jù)集,構建樹
        localD = {}
        # 過濾頻繁項集
        for item in tranSet:
            if item in freqItemSet:
                localD[item] = headerTable[item][0]
        if len(localD) > 0:
            # 排序
            orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: p[1], reverse=True)]
            # 使用排序后的頻繁項集對樹進行填充
            updateTree(orderedItems, retTree, headerTable, count)
    return retTree, headerTable

def updateTree(items, inTree, headerTable, count):
    # 檢查items[0]是否已在子節(jié)點
    if items[0] in inTree.children:
        inTree.children[items[0]].inc(count) # 是的話直接增加count
    else:   # 否則items[0]加到inTree.children
        inTree.children[items[0]] = treeNode(items[0], count, inTree)
        # 更新頭指針表
        if headerTable[items[0]][1] == None:
            headerTable[items[0]][1] = inTree.children[items[0]]
        else:
            updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
    # 遞歸填充剩下的項
    if len(items) > 1:
        updateTree(items[1::], inTree.children[items[0]], headerTable, count)
        
def updateHeader(nodeToTest, targetNode):   
    while (nodeToTest.nodeLink != None):  
        nodeToTest = nodeToTest.nodeLink
    nodeToTest.nodeLink = targetNode

第一個函數(shù)createTree()有兩個參數(shù)淫奔,數(shù)據(jù)集和最小支持度山涡。這里支持度的定義跟Apriori算法的不一樣,是元素項出現(xiàn)的次數(shù)。樹構建過程中一共遍歷數(shù)據(jù)集兩次鸭丛。

為了FP樹生長(growth)竞穷,需調用updateTree()進行填充。也就是圖3的過程鳞溉。

updateHeader()函數(shù)用于更新頭指針表瘾带,確保節(jié)點鏈接指向樹中該元素項的每一個實例。

接下來熟菲,模擬一個簡單數(shù)據(jù)集月弛,并實際構建FP樹。

def createSimpDat():
    simpDat = [['r', 'z', 'h', 'j', 'p'],
               ['z', 'y', 'x', 'w', 'v', 'u', 't', 's'],
               ['z'],
               ['r', 'x', 'n', 'o', 's'],
               ['y', 'r', 'x', 'z', 'q', 't', 'p'],
               ['y', 'z', 'x', 'e', 'q', 's', 't', 'm']]
    return simpDat

def transToDict(dataSet):
    retDict = {}
    for trans in dataSet:
        retDict[frozenset(trans)] = 1
    return retDict

data = transToDict(createSimpDat())
FPTree, headerTable = createTree(data, 3)

看一下data

也就是前面表中的數(shù)據(jù)科盛。

再看一下FP樹


對照最開始的圖1帽衙,可以發(fā)現(xiàn)是一樣的結構。

構建好FP樹后贞绵,就可以使用它來進行頻繁項集挖掘了厉萝。


畫圖不易吖~都看到最后了,要不~點個贊榨崩?加波關注谴垫?

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市母蛛,隨后出現(xiàn)的幾起案子翩剪,更是在濱河造成了極大的恐慌,老刑警劉巖彩郊,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件前弯,死亡現(xiàn)場離奇詭異,居然都是意外死亡秫逝,警方通過查閱死者的電腦和手機恕出,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來违帆,“玉大人浙巫,你說我怎么就攤上這事∷⒑螅” “怎么了的畴?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長尝胆。 經(jīng)常有香客問我丧裁,道長,這世上最難降的妖魔是什么班巩? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任渣慕,我火速辦了婚禮嘶炭,結果婚禮上,老公的妹妹穿的比我還像新娘逊桦。我一直安慰自己眨猎,他們只是感情好,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布强经。 她就那樣靜靜地躺著睡陪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匿情。 梳的紋絲不亂的頭發(fā)上兰迫,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機與錄音炬称,去河邊找鬼肺素。 笑死洽腺,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播办桨,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼瞳浦,長吁一口氣:“原來是場噩夢啊……” “哼链方!你這毒婦竟也來了拧粪?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朽缴,失蹤者是張志新(化名)和其女友劉穎善玫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體密强,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡茅郎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了誓斥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只洒。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劳坑,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情成畦,我是刑警寧澤距芬,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站循帐,受9級特大地震影響框仔,放射性物質發(fā)生泄漏。R本人自食惡果不足惜拄养,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一离斩、第九天 我趴在偏房一處隱蔽的房頂上張望银舱。 院中可真熱鬧,春花似錦跛梗、人聲如沸寻馏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诚欠。三九已至,卻和暖如春漾岳,著一層夾襖步出監(jiān)牢的瞬間轰绵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工尼荆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留左腔,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓捅儒,卻偏偏與公主長得像翔悠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子野芒,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內容