日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

机器学习之手把手实现,第 2 部分 频繁项集与关联规则 FP-growth 的原理和实现...

發布時間:2025/4/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习之手把手实现,第 2 部分 频繁项集与关联规则 FP-growth 的原理和实现... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://www.ibm.com/developerworks/cn/analytics/library/machine-learning-hands-on2-fp-growth/index.html?ca=drs-

本文將介紹機器學習領域經典的 FP-growth(Frequent Pattern Growth)模型,它是目前業界經典的頻繁項集和關聯規則挖掘的算法。相比于 Apriori 模型,FP-growth 模型只需要掃描數據庫兩次,極大得減少了數據讀取次數并顯著得提升了算法效率。您將看到 FP-growth 的原理介紹、FP-growth 實現步驟和詳解、FP-growth 實現代碼以及用 FP-growth 解決實際的頻繁項集和關聯規則挖掘問題。通過閱讀本文,您會對 FP-growth 的原理了如指掌,并可以自己開發出 FP-growth 的實現代碼。

從啤酒和尿布引出的頻繁項集

在機器學習系列文章的第一篇中,主要介紹了支持向量機 SVM 模型的原理和實現。在文章一開始,筆者提到機器學習主要分為四大類,分別是分類,聚類,回歸和關聯分析。第一篇中的 SVM 就屬于分類。那么下面筆者開始介紹關聯分析。關聯分析分為頻繁項集挖掘和關聯規則挖掘。

生活中的數據本身包含著各種規律,機器學習模型可以從數據中挖掘出這些規律,啤酒與尿布就是一個典型的例子。有研究發現,在超市的訂單記錄中,啤酒和尿布總是頻繁共同出現在同一條訂單記錄里。換句話說,買尿布的人,往往會順手買啤酒。這就引出了本文的主題之一,即頻繁項集。頻繁項集是在數據庫中大量頻繁出現的數據集合。那么發現這些頻繁項集有什么意義呢?

  • 用于制定營銷策略。如同啤酒與尿布的例子,超市如果將啤酒和尿布放在相鄰的位置,會增加兩者的銷量。還可用于制定打折促銷活動,給買了啤酒和尿布的客戶打折,也可以增加銷量。
  • 用于發現共現詞。這種場景其實我們經常會遇到。當我們在瀏覽器中輸入"頻繁項集"時,瀏覽器自動彈出如"頻繁項集 置信度","頻繁項集 關聯規則"等備選記錄,我們每每都會感嘆瀏覽器的智能,其實這里的秘訣就是頻繁項集。也就是說,在大量的用戶搜索記錄中,"頻繁項集"和"置信度"共同出現在了大多數的搜索記錄中。同理,"頻繁項集"和"關聯規則"也頻繁得共同出現在搜索記錄中。
  • 用于發現事物的熱點信息。從新聞報道和微博中獲取關于某事物的相關文檔,然后應用頻繁項集挖掘算法可以得到該事物的熱點新聞。
  • 主流的頻繁項集挖掘算法有 Apriori 和 FP-growth。其中 Apriori 算法需要多次掃描數據庫,這就使得該算法本身不適合大數據量。FP-growth,即 Frequent Pattern Growth,它通過構建 FP 樹(即 Frequent Pattern Tree)這樣的數據結構,巧妙得將數據存儲在 FP 樹中,只需要在構建 FP 樹時掃描數據庫兩次,后續處理就不需要再訪問數據庫了。這種特性使得 FP-growth 算法比 Apriori 算法速度快。FP 樹是一種前綴樹,由頻繁項的前綴構成,具體細節會在頻繁項集挖掘原理一節介紹。挖掘出頻繁項集后,可以從頻繁項集中進一步挖掘關聯規則。

    關聯規則簡介

    關聯規則是在頻繁項集的基礎上得到的。關聯規則指由集合 A,可以在某置信度下推出集合 B。通俗來說,就是如果 A 發生了,那么 B 也很有可能會發生。舉個例子,有關聯規則如:{'雞蛋', '面包'} -> {'牛奶'},該規則的置信度是 0.9,意味著在所有買了雞蛋和面包的客戶中,有 90%的客戶還買了牛奶。關聯規則可以用來發現很多有趣的規律。這其中需要先闡明兩個概念:支持度和置信度。

    支持度 Support

    支持度指某頻繁項集在整個數據集中的比例。假設數據集有 10 條記錄,包含{'雞蛋', '面包'}的有 5 條記錄,那么{'雞蛋', '面包'}的支持度就是 5/10 = 0.5。

    置信度 Confidence

    置信度是針對某個關聯規則定義的。有關聯規則如{'雞蛋', '面包'} -> {'牛奶'},它的置信度計算公式為{'雞蛋', '面包', '牛奶'}的支持度/{'雞蛋', '面包'}的支持度。假設{'雞蛋', '面包', '牛奶'}的支持度為 0.45,{'雞蛋', '面包'}的支持度為 0.5,則{'雞蛋', '面包'} -> {'牛奶'}的置信度為 0.45 / 0.5 = 0.9。

    關聯規則用于發現 if -> then 這樣的規則,并可以給出這條規則的可信度(即置信度)。現實場景中可以用來發現很多規律,下面舉個例子。在信息安全領域,需要根據已有流量數據制定規則,來判斷是否觸發安全報警。如規則{'數據包大','多個 ip 地址同時發送數據'} -> {'異常'},該規則的置信度為 0.85。這條規則表示,當流量數據包大,并有多個 ip 地址同時向目標 ip 發送數據時,則有 85%的概率存在異常,需要觸發報警。

    頻繁項集挖掘原理

    頻繁項集挖掘分為構建 FP 樹,和從 FP 樹中挖掘頻繁項集兩步。本節用如下表所示的數據集作為例子展開,該示例數據集共四條數據。

    表 1. 示例數據集
    數據集

    構建 FP 樹

    構建 FP 樹時,首先統計數據集中各個元素出現的頻數,將頻數小于最小支持度的元素刪除,然后將數據集中的各條記錄按出現頻數排序,剩下的這些元素稱為頻繁項;接著,用更新后的數據集中的每條記錄構建 FP 樹,同時更新頭指針表。頭指針表包含所有頻繁項及它們的頻數,還有每個頻繁項指向下一個相同元素的指針,該指針主要在挖掘 FP 樹時使用。下面用上文提到的數據集展開說明,假設最小支持度為 2。

    首先,統計數據集中各元素出現的次數,得 a 出現 4 次, b 出現 3 次, c 出現 2 次, d 出現 2 次, e 出現 1 次。

    接著,將出現次數小于最小支持度 2 的元素(即 e)在數據集中刪除,并將數據集按出現次數由高到低排序,得表 2。

    表 2. 更新后的數據集
    數據集

    然后,用更新后的數據集中的記錄創建 FP 樹,并同時更新頭指針表。創建 FP 樹時,當待添加的記錄與 FP 樹中的路徑相同,則只需更新元素對應的頻數;如果待添加的記錄與 FP 樹存在不一致,則在不一致的地方分叉,創建新的結點。如圖 1-4 所示。注意,FP 樹的根節點是 null。

    圖 1. 向 FP 樹添加第一條記錄{a,b,c}

    圖 2. 向 FP 樹添加第二條記錄{a,b,c,d}

    圖 3. 向 FP 樹添加第三條記錄{a,d}

    圖 4. 向 FP 樹添加第四條記錄{a,b}

    挖掘頻繁項集

    得到 FP 樹后,需要對每一個頻繁項,逐個挖掘頻繁項集。具體過程為:首先獲得頻繁項的前綴路徑,然后將前綴路徑作為新的數據集,以此構建前綴路徑的條件 FP 樹。然后對條件 FP 樹中的每個頻繁項,獲得前綴路徑并以此構建新的條件 FP 樹。不斷迭代,直到條件 FP 樹中只包含一個頻繁項為止。下面以元素 c 為例,從上文圖 4 創建好的 FP 樹中挖掘頻繁項集。

    首先,獲得以 c 元素的前綴路徑{a:2,b:2},注意此處 a 和 b 的頻數為 2 是因為 c 的頻數為 2,所以與 c 共同出現的 a 和 b 的頻數就都為 2。

    接著,創建條件 FP 樹,具體的創建過程和上一節創建 FP 樹的過程一樣,如圖 5 所示。

    圖 5. c 元素的前綴路徑構成的條件 FP 樹

    注意此時頭指針表中包含兩個元素,所以對每個元素,需要獲得前綴路徑,并將前綴路徑創建成條件 FP 樹,直到條件 FP 樹中只包含一個元素時返回。

  • 對元素 a,獲得前綴路徑為{},則頻繁項集返回{c,a};
  • 對元素 b,獲得前綴路徑{a},則將前綴路徑創建成條件 FP 樹,如圖 6 所示。注意此時條件 FP 樹中只包含一個元素,故返回頻繁項集{c,b,a}。由于元素 b 也是頻繁項,所以{c,b}也是頻繁項集。
  • 再加上{c}本身就是頻繁項集,所以 c 對應的頻繁項集有:{c} {c,a} {c,b} {c,b,a}。

    圖 6. b 元素的前綴路徑構成的條件 FP 樹

    將其他元素 a,b,d 同樣按照上述對 c 的操作,得到表 3 所示頻繁項集。

    表 3. 元素 a,b,c,d 對應的頻繁項集
    元素頻繁項集

    關聯規則挖掘原理

    關聯規則挖掘首先需要對上文得到的頻繁項集構建所有可能的規則,然后對每條規則逐個計算置信度,輸出置信度大于最小置信度的所有規則。以頻繁項集{a,b,c}為例,構建所有可能的規則:{b,c} -> {a}, {a,c} -> {b},{a,b} -> {c},{c} -> {a,b},{b} -> {a,c},{a} -> {b,c}。對每條規則計算置信度后,輸出滿足要求的規則即可。

    實現步驟: 自己動手實現 FP-growth

    以上都為理論部分,下面開始介紹如何自己動手實現代碼。

    首先,需要創建一個樹形的數據結構,叫做 FP 樹。如清單 1 所示,該樹結構包含結點名稱 nodeName,結點元素出現頻數 count,父節點 nodeParent,指向下一個相同元素的指針 nextSimilarItem,子節點集合 children。

    清單 1. FP 樹結構
    1 2 3 4 5 6 7 class TreeNode: ????def __init__(self, nodeName, count, nodeParent): ????????self.nodeName = nodeName ????????self.count = count ????????self.nodeParent = nodeParent ????????self.nextSimilarItem = None ????????self.children = {}

    接著,用第一步構造出的數據結構來創建 FP 樹。如清單 2 所示,代碼主要分為兩層。第一層,掃描數據庫,統計出各個元素的出現頻數;第二層,掃描數據庫,對每一條數據記錄,將數據記錄中不包含在頻繁元素中的元素刪除,然后將數據記錄中的元素按出現頻數排序。將數據記錄逐條插入 FP 樹中,不斷更新 FP 樹,更新的過程會在清單 3 中介紹。

    清單 2. 創建 FP 樹
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def createFPTree(frozenDataSet, minSupport): ????#scan dataset at the first time, filter out items which are less than minSupport ????headPointTable = {} ????for items in frozenDataSet: ????????for item in items: ????????????headPointTable[item] = headPointTable.get(item, 0) + frozenDataSet[items] ????headPointTable = {k:v for k,v in headPointTable.items() if v >= minSupport} ????frequentItems = set(headPointTable.keys()) ????if len(frequentItems) == 0: return None, None ????for k in headPointTable: ????????headPointTable[k] = [headPointTable[k], None] ????fptree = TreeNode("null", 1, None) ????#scan dataset at the second time, filter out items for each record ????for items,count in frozenDataSet.items(): ????????frequentItemsInRecord = {} ????????for item in items: ????????????if item in frequentItems: ????????????????frequentItemsInRecord[item] = headPointTable[item][0] ????????if len(frequentItemsInRecord) > 0: ????????????orderedFrequentItems = [v[0] for v in sorted(frequentItemsInRecord.items(), key=lambda v:v[1], reverse = True)] ????????????updateFPTree(fptree, orderedFrequentItems, headPointTable, count) ????return fptree, headPointTable

    清單 3 主要用來更新 FP 樹,這里用到了遞歸的技巧。每次遞歸迭代中,處理數據記錄中的第一個元素處理,如果該元素是 fptree 節點的子節點,則只增加該子節點的 count 樹,否則,需要新創建一個 TreeNode 節點,然后將其賦給 fptree 節點的子節點,并更新頭指針表關于下一個相同元素指針的信息。迭代的停止條件是當前迭代的數據記錄長度小于等于 1。

    清單 3. 更新 FP 樹
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def updateFPTree(fptree, orderedFrequentItems, headPointTable, count): ????#handle the first item ????if orderedFrequentItems[0] in fptree.children: ????????fptree.children[orderedFrequentItems[0]].increaseC(count) ????else: ????????fptree.children[orderedFrequentItems[0]] = TreeNode(orderedFrequentItems[0], count, fptree) ????????#update headPointTable ????????if headPointTable[orderedFrequentItems[0]][1] == None: ????????????headPointTable[orderedFrequentItems[0]][1] = fptree.children[orderedFrequentItems[0]] ????????else: ????????????updateHeadPointTable(headPointTable[orderedFrequentItems[0]][1], fptree.children[orderedFrequentItems[0]]) ????#handle other items except the first item ????if(len(orderedFrequentItems) > 1): ????????updateFPTree(fptree.children[orderedFrequentItems[0]], orderedFrequentItems[1::], headPointTable, count)

    清單 4 開始挖掘頻繁項集,這里也是遞歸迭代的思路。對于頭指針表中的每一個元素,首先獲取該元素結尾的所有前綴路徑,然后將所有前綴路徑作為新的數據集傳入 createFPTree 函數中以創建條件 FP 樹。然后對條件 FP 樹對應的頭指針表中的每一個元素,開始獲取前綴路徑,并創建新的條件 FP 樹。這兩步不斷重復,直到條件 FP 樹中只有一個元素為止。

    清單 4. 挖掘頻繁項集
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def mineFPTree(headPointTable, prefix, frequentPatterns, minSupport): ????#for each item in headPointTable, find conditional prefix path, create conditional fptree, then iterate until there is only one element in conditional fptree ????headPointItems = [v[0] for v in sorted(headPointTable.items(), key = lambda v:v[1][0])] ????if(len(headPointItems) == 0): return ????for headPointItem in headPointItems: ????????newPrefix = prefix.copy() ????????newPrefix.add(headPointItem) ????????support = headPointTable[headPointItem][0] ????????frequentPatterns[frozenset(newPrefix)] = support ????????prefixPath = getPrefixPath(headPointTable, headPointItem) ????????if(prefixPath != {}): ????????????conditionalFPtree, conditionalHeadPointTable = createFPTree(prefixPath, minSupport) ????????????if conditionalHeadPointTable != None: ????????????????mineFPTree(conditionalHeadPointTable, newPrefix, frequentPatterns, minSupport)

    清單 5 展示了獲取前綴路徑的步驟。對于每一個相同元素,通過父節點指針不斷向上遍歷,所得的路徑就是該元素的前綴路徑。

    清單 5. 獲取前綴路徑
    1 2 3 4 5 6 7 8 9 10 11 12 13 def getPrefixPath(headPointTable, headPointItem): ????prefixPath = {} ????beginNode = headPointTable[headPointItem][1] ????prefixs = ascendTree(beginNode) ????if((prefixs != [])): ????????prefixPath[frozenset(prefixs)] = beginNode.count ????while(beginNode.nextSimilarItem != None): ????????beginNode = beginNode.nextSimilarItem ????????prefixs = ascendTree(beginNode) ????????if (prefixs != []): ????????????prefixPath[frozenset(prefixs)] = beginNode.count ????return prefixPath

    清單 6 展示了挖掘關聯規則的代碼,這里也用到了遞歸迭代的技巧。對于每一個頻繁項集,構造所有可能的關聯規則,然后對每一個關聯規則計算置信度,輸出置信度大于閾值的關聯規則。

    清單 6. 挖掘關聯規則
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def rulesGenerator(frequentPatterns, minConf, rules): ????for frequentset in frequentPatterns: ????????if(len(frequentset) > 1): ????????????getRules(frequentset,frequentset, rules, frequentPatterns, minConf) def getRules(frequentset,currentset, rules, frequentPatterns, minConf): ????for frequentElem in currentset: ????????subSet = removeStr(currentset, frequentElem) ????????confidence = frequentPatterns[frequentset] / frequentPatterns[subSet] ????????if (confidence >= minConf): ????????????flag = False ????????????for rule in rules: ????????????????if(rule[0] == subSet and rule[1] == frequentset - subSet): ????????????????????flag = True ????????????if(flag == False): ????????????????rules.append((subSet, frequentset - subSet, confidence)) ????????????if(len(subSet) >= 2): ????????????????getRules(frequentset, subSet, rules, frequentPatterns, minConf)

    代碼下載 (code downloads)

    本文所有 FP-growth 實現代碼可在文末下載。

    本文數據集簡介

    圖 7. 數據集樣例

    數據集是購物車數據。每一條代表了一條購物車信息。目的是要挖掘出在購物車中頻繁共同出現的集合,并根據此頻繁項集挖掘出關聯規則。關聯規則暗示頻繁項集之間存在的關系,如購買了面包的人,有很高的可能性會同時購買牛奶。

    應用示例: 應用實現的 FP-growth 解決實際問題

    清單 7. 用 FP-growth 解決實際問題
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if __name__=='__main__': ????print("fptree:") ????dataSet = loadDataSet() ????frozenDataSet = transfer2FrozenDataSet(dataSet) ????minSupport = 3 ????fptree, headPointTable = createFPTree(frozenDataSet, minSupport) ????fptree.disp() ????frequentPatterns = {} ????prefix = set([]) ????mineFPTree(headPointTable, prefix, frequentPatterns, minSupport) ????print("frequent patterns:") ????print(frequentPatterns) ????minConf = 0.6 ????rules = [] ????rulesGenerator(frequentPatterns, minConf, rules) ????print("association rules:") ????print(rules)

    清單 5 中的代碼首先加載數據集,然后通過調用前面實現的 FP-growth 代碼,先是構造 FP 樹,接著從 FP 樹中挖掘頻繁項集,最后從頻繁項集中產生關聯規則,并輸出置信度。

    表 4. 頻繁項集的結果示例
    頻繁項集支持度 (Support)

    從表 4 中可以看出,鞋子與襪子,牛奶與面包,面包與雞蛋,牛奶與雞蛋,手套與襪子,牛奶、雞蛋與面包等項在數據集中共同出現得很頻繁。

    表 5. 關聯規則的結果示例
    關聯規則置信度 (Confidence)

    從表 5 中可以看出某人購買了鞋子,極有可能會同時購買襪子;某人購買了雞蛋與面包,極有可能會購買牛奶;某人購買了手套,極有可能會購買襪子。但是需注意,關聯規則反過來不一定同樣成立,拿第一條和第二條結果為例,由鞋子推出襪子的置信度是 1.0,但是反過來,由襪子推出鞋子的置信度只有 0.75,而并不是 1.0。

    總結

    本文首先介紹了頻繁項集和關聯規則在現實場景中的應用,接著介紹了頻繁項集和關聯規則挖掘的原理,然后通過代碼樣例,介紹了在自己動手實現 FP-growth 模型時的思路。最后,用購物車數據展示了如何應用 FP-growth 解決實際問題。需要注意的是,FP-growth 算法本身對于海量數據仍然會很慢,雖然其只需要掃描數據庫兩次,但是對于海量數據在內存中建立一份統一的 FP 樹結構是不大現實的。這就需要考慮采用并行計算的思路來并發實現 FP-growth,利用多臺電腦并行執行 FP-growth,從而加速運算。并行 FP-growth 的具體實現方法可以參考文獻 2 所列的論文。由于篇幅有限,這部分內容不在本次內容中展開,預計后期會對這部分內容進行專門介紹。

    參考資源

    本文用到的參考文獻如下:

      • 參考 Peter Harrington 著《機器學習實戰》,了解 FP-growth 模型。
      • Zhang D, Zhang D, Zhang D, et al. Pfp: parallel fp-growth for query recommendation[C]// ACM Conference on Recommender Systems. ACM, 2008:107-114.

    轉載于:https://www.cnblogs.com/davidwang456/articles/8926985.html

    總結

    以上是生活随笔為你收集整理的机器学习之手把手实现,第 2 部分 频繁项集与关联规则 FP-growth 的原理和实现...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。