什么是FP-growth频繁项集挖掘?

一、概念

        FP-Growth(Frequent Pattern Growth)算法是一种用于从事务数据库中挖掘频繁项集的高效算法。它是关联规则挖掘中的一种重要方法,能够在不产生候选项集的情况下找到频繁项集。FP-Growth算法通过构建一种称为FP-Tree(频繁模式树)的数据结构来实现这一目标。

二、原理

1. FP-Tree构建

        FP-Growth算法的第一步是构建FP-Tree。FP-Tree是一种紧凑的数据结构,用于存储事务数据库中的频繁项集。构建FP-Tree的步骤如下:

  1. 扫描事务数据库:第一次扫描事务数据库,计算每个项的频次(支持度)。
  2. 移除不频繁项:根据预定义的最小支持度阈值,移除不频繁的项。
  3. 项排序:对每个事务中的项按照频次从高到低排序。
  4. 构建FP-Tree:第二次扫描事务数据库,将每个事务插入FP-Tree中。插入时,按照排序后的顺序插入,若树中已有相同前缀路径,则共享该路径。

2. 挖掘频繁项集

        在构建好FP-Tree之后,FP-Growth算法通过递归地挖掘FP-Tree来找到所有频繁项集。具体步骤如下:

  1. 从FP-Tree中提取条件模式基:对于每个频繁项,提取其条件模式基(即包含该项的所有路径)。
  2. 构建条件FP-Tree:根据条件模式基,构建条件FP-Tree。
  3. 递归挖掘条件FP-Tree:对条件FP-Tree进行递归挖掘,找到所有频繁项集。

三、python实现

1、手撕版

class TreeNode:
    def __init__(self, name, count, parent):
        # 初始化树节点
        self.name = name  # 节点名称
        self.count = count  # 节点计数
        self.parent = parent  # 父节点
        self.children = {}  # 子节点
        self.nodeLink = None  # 链接到相似节点

    def increment(self, count):
        # 增加节点计数
        self.count += count

def update_header(node, targetNode):
    # 更新头指针表,确保节点链接到链表的最后一个节点
    while node.nodeLink is not None:
        node = node.nodeLink
    node.nodeLink = targetNode

def update_tree(items, inTree, headerTable, count):
    # 更新FP树
    if items[0] in inTree.children:
        # 如果第一个元素在子节点中,增加计数
        inTree.children[items[0]].increment(count)
    else:
        # 否则创建新的子节点
        inTree.children[items[0]] = TreeNode(items[0], count, inTree)
        if headerTable[items[0]][1] is None:
            # 更新头指针表
            headerTable[items[0]][1] = inTree.children[items[0]]
        else:
            update_header(headerTable[items[0]][1], inTree.children[items[0]])
    if len(items) > 1:
        # 递归更新树
        update_tree(items[1:], inTree.children[items[0]], headerTable, count)

def create_tree(dataSet, minSup=1):
    # 创建FP树
    headerTable = {}
    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())
    if len(freqItemSet) == 0: return None, None
    for k in headerTable:
        headerTable[k] = [headerTable[k], None]
    retTree = TreeNode('Null Set', 1, None)
    for tranSet, count in dataSet.items():
        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)]
            update_tree(orderedItems, retTree, headerTable, count)
    return retTree, headerTable

def ascend_tree(leafNode, prefixPath):
    # 递归上升树,收集前缀路径
    if leafNode.parent is not None:
        prefixPath.append(leafNode.name)
        ascend_tree(leafNode.parent, prefixPath)

def find_prefix_path(basePat, treeNode):
    # 查找前缀路径
    condPats = {}
    while treeNode is not None:
        prefixPath = []
        ascend_tree(treeNode, prefixPath)
        if len(prefixPath) > 1:
            condPats[frozenset(prefixPath[1:])] = treeNode.count
        treeNode = treeNode.nodeLink
    return condPats

def mine_tree(inTree, headerTable, minSup, preFix, freqItemList):
    # 挖掘FP树
    bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p: p[1][0])]
    for basePat in bigL:
        newFreqSet = preFix.copy()
        newFreqSet.add(basePat)
        freqItemList.append(newFreqSet)
        condPattBases = find_prefix_path(basePat, headerTable[basePat][1])
        myCondTree, myHead = create_tree(condPattBases, minSup)
        if myHead is not None:
            mine_tree(myCondTree, myHead, minSup, newFreqSet, freqItemList)

def load_simp_dat():
    simp_dat = [['牛奶', '面包', '啤酒'],
                ['牛奶', '面包'],
                ['牛奶', '啤酒'],
                ['面包', '啤酒'],
                ['牛奶', '面包', '啤酒', '鸡蛋'],
                ['面包', '鸡蛋']]
    return simp_dat

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

simp_dat = load_simp_dat()
init_set = create_init_set(simp_dat)
my_fp_tree, my_header_tab = create_tree(init_set, 2)

freq_items = []
mine_tree(my_fp_tree, my_header_tab, 2, set([]), freq_items)

print("频繁项集:")
for itemset in freq_items:
    print(itemset)

2、工程实现

import pyfpgrowth

transactions = [['牛奶', '面包', '啤酒'],
                ['牛奶', '面包'],
                ['牛奶', '啤酒'],
                ['面包', '啤酒'],
                ['牛奶', '面包', '啤酒', '鸡蛋'],
                ['面包', '鸡蛋']]

min_sup = 2  # 绝对支持度计数

# 自动处理数据预处理
patterns = pyfpgrowth.find_frequent_patterns(transactions, min_sup)
rules = pyfpgrowth.generate_association_rules(patterns, 0.7)  # 置信度阈值

# 结果展示
print("频繁项集:")
for itemset, support in patterns.items():
    print(f"{set(itemset)}: {support}")
print("\n关联规则:")
for ante, cons in rules.items():
    print(f"{set(ante)} => {set(cons[0])} [conf={cons[1]:.2f}]")

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值