关联规则挖掘的目的是挖掘不同物品(item)之前的相关性,啤酒和尿布的故事就是一个典型的成功例子。关联规则挖掘思想简单高效,在广告推荐领域也有较多的应用,主要用于推荐模型落地前的流量探索以及构建规则引擎探寻高价值流量等。本文主要介绍关联规则挖掘常用的两种算法,即Aprior算法和Fpgrowth算法。
  正式开始介绍这两种算法前,先简单讲述一下关联规则挖掘常用的几个概念。

a: 几个重要的概念

  1. 支持度: 某个物品组合出现的次数与总次数的比例;
  2. 置信度: 表示A物品出现时,会有多大的概率出现B,假如物品A出现了Na次,AB同时出现了Nab次,那么置信度(A–>B)=Nab/Na
  3. 提升度: 物品A出现对物品B出现概率的提升程度,也就是B在A集合中出现的概率与B在整体集合出现概率的比值,提升度 (A→B)= 置信度 (A→B)/ 支持度 (B)。
    a. 提升度 (A→B)>1:代表有提升;  正向规则
    b. 提升度 (A→B)=1:代表有没有提升,也没有下降;   无效规则
    c. 提升度 (A→B)<1:代表有下降;   负向规则

Apriori算法

  Apriori算法的原理一言以蔽之,就是不断查找频繁项集的过程,而频繁项集就是我们需要界定的参数,我们界定一个支持度阈值S,当该物品组合的出现频率高于S时,我们认为该物品组合为频繁项集,对小于S的物品组合算法会忽略。
  搞清楚频繁项集的含义之后,Apriori算法的实现原理就非常简单了,这里在介绍一个补充概念,规则包括的物品数量n,大致如下:

  1. 当n=1时,计算每一个物品的支持度Si1,保留Si1>S的物品集合F1;
  2. 当n=2时,将F1中的物品两两组合,计算每个组合的支持度Si2,保留Si2>S的物品集合F2;
  3. 当n=3时,将F2中的物品两两组合(组合后去重),仅保留长度为3的组合,计算每个组合的支持度Si3,保留Si3>S的物品集合F3;
  4. …以此类推,直到Fn集合为空;

  如果某个物品的支持度不满足阈值,那么其任一两两组合也必不能满足条件;同理,如果某两两组合的支持度不满足阈值,那么其构成的任一三物品组合也必不能满足条件。这就是可以将每一次计算的结果建立在上一次结果的基础上的原因,大大减少计算量。
   Apriori算法的python包很多,这里不给源码了,调用代码如下:

from efficient_apriori import apriori
data = [('牛奶', '面包'),('牛奶', '面包', '火腿'),('面包', '火腿', '可乐'),('火腿', '可乐', '方便面'),('面包', '火腿', '可乐', '方便面')
]itemsets, rules = apriori(data, min_support=0.6,  min_confidence=0.3, verbosity=0)
print(itemsets, rules)
  • 该包的调用结果不显示支持度的信息,需要修改源码,这里省略该过程。
  • 程序运行结果如下:
({1: {('面包',): 4, ('火腿',): 4, ('可乐',): 3},2: {('可乐', '火腿'): 3, ('火腿', '面包'): 3}},[{火腿} -> {可乐} (conf: 0.750, supp: 0.600, lift: 1.250, conv: 1.600),{可乐} -> {火腿} (conf: 1.000, supp: 0.600, lift: 1.250, conv: 200000000.000),{面包} -> {火腿} (conf: 0.750, supp: 0.600, lift: 0.938, conv: 0.800),{火腿} -> {面包} (conf: 0.750, supp: 0.600, lift: 0.938, conv: 0.800)])
  • conf: 置信度,supp: 支持度,lift: 提升度。
  • conv(A—>B)表示,B物品在总集合中不出现的概率与B物品在A存在集合中不出现概率的比值。

Fp-growth算法

  Fp-growth算法是Apriori算法的改进版本,本质上没啥区别。Fp-growth算法的原理很简单,该算法使用了一种称为频繁模式树的数据结构。FP-tree是一种特殊的前缀树,由频繁项头表和项前缀树构成,大致过程如下:

  1. 扫描数据库一遍.得到频繁项的集合F和每个频繁项的支持度.把F按支持度递降排序,结果记为L(A-val=6、B-val=5、C-val=4、D-val=4)(有序的F1).
  2. 创建FP-tree的根节点,记为T,并且标记为’root’,然后L的每项做如下的步骤:
    a. 根据L中的顺序,将A作为第一个节点,在数据库中扫描,如果出现AB,那么从A延伸出一个节点B,B对应的val+1(val初始为0),如果出现AC,那么从A延伸出一个节点C,C对应的val+1;
    b. 从A节点的子节点B出发,假如出现ABC,从那么从B延伸出一个节点C,C对应的val+1;
    c. …以此类推,直到该路径对应子节点不在满足条件(支持度阈值);

   Fp-growth算法的原理相对比较复杂,开源的python包比较少,这里附上对应的源码:

# -*- coding: utf-8 -*-
from tqdm import tqdm
import time
import psutil
import osdef load_data():  # 根据路径加载数据集ans = []  # 将数据保存到该数组reader = [('牛奶', '面包'),('牛奶', '面包', '火腿'),('面包', '火腿', '可乐'),('火腿', '可乐', '方便面'),('面包', '火腿', '可乐', '方便面')]for row in reader:row = list(set(row))  # 去重,排序row.sort()ans.append(row)  # 将添加好的数据添加到数组return ans  # 返回处理好的数据集,为二维数组def show_confidence(rule):index = 1for item in rule:s = " {:<4d}  {:.3f}        {}=>{}".format(index, item[2], str(list(item[0])), str(list(item[1])))index += 1print(s)class Node:def __init__(self, node_name, count, parentNode):self.name = node_nameself.count = countself.nodeLink = None  # 根据nideLink可以找到整棵树中所有nodename一样的节点self.parent = parentNode  # 父亲节点self.children = {}  # 子节点{节点名字:节点地址}class Fp_growth_plus():def data_compress(self, data_set):data_dic = {}for i in data_set:if frozenset(i) not in data_dic:data_dic[frozenset(i)] = 1else:data_dic[frozenset(i)] += 1return data_dicdef update_header(self, node, targetNode):  # 更新headertable中的node节点形成的链表while node.nodeLink != None:node = node.nodeLinknode.nodeLink = targetNodedef update_fptree(self, items, count, node, headerTable):  # 用于更新fptreeif items[0] in node.children:# 判断items的第一个结点是否已作为子结点node.children[items[0]].count += countelse:# 创建新的分支node.children[items[0]] = Node(items[0], count, node)# 更新相应频繁项集的链表,往后添加if headerTable[items[0]][1] == None:headerTable[items[0]][1] = node.children[items[0]]else:self.update_header(headerTable[items[0]][1], node.children[items[0]])# 递归if len(items) > 1:self.update_fptree(items[1:], count, node.children[items[0]], headerTable)def create_fptree(self, data_dic, min_support, flag=False):  # 建树主函数item_count = {}  # 统计各项出现次数for t in data_dic:  # 第一次遍历,得到频繁一项集for item in t:if item not in item_count:item_count[item] = data_dic[t]else:item_count[item] += data_dic[t]headerTable = {}for k in item_count:  # 剔除不满足最小支持度的项if item_count[k] >= min_support:headerTable[k] = item_count[k]freqItemSet = set(headerTable.keys())  # 满足最小支持度的频繁项集if len(freqItemSet) == 0:return None, Nonefor k in headerTable:headerTable[k] = [headerTable[k], None]  # element: [count, node]tree_header = Node('head node', 1, None)if flag:ite = tqdm(data_dic)else:ite = data_dicfor t in ite:  # 第二次遍历,建树localD = {}for item in t:if item in freqItemSet:  # 过滤,只取该样本中满足最小支持度的频繁项localD[item] = headerTable[item][0]  # element : countif len(localD) > 0:# 根据全局频数从大到小对单样本排序order_item = [v[0] for v in sorted(localD.items(), key=lambda x: x[1], reverse=True)]# 用过滤且排序后的样本更新树self.update_fptree(order_item, data_dic[t], tree_header, headerTable)return tree_header, headerTabledef find_path(self, node, nodepath):'''递归将node的父节点添加到路径'''if node.parent != None:nodepath.append(node.parent.name)self.find_path(node.parent, nodepath)def find_cond_pattern_base(self, node_name, headerTable):'''根据节点名字,找出所有条件模式基'''treeNode = headerTable[node_name][1]cond_pat_base = {}  # 保存所有条件模式基while treeNode != None:nodepath = []self.find_path(treeNode, nodepath)if len(nodepath) > 1:cond_pat_base[frozenset(nodepath[:-1])] = treeNode.counttreeNode = treeNode.nodeLinkreturn cond_pat_basedef create_cond_fptree(self, headerTable, min_support, temp, freq_items, support_data):# 最开始的频繁项集是headerTable中的各元素freqs = [v[0] for v in sorted(headerTable.items(), key=lambda p: p[1][0])]  # 根据频繁项的总频次排序for freq in freqs:  # 对每个频繁项freq_set = temp.copy()freq_set.add(freq)freq_items.add(frozenset(freq_set))if frozenset(freq_set) not in support_data:  # 检查该频繁项是否在support_data中support_data[frozenset(freq_set)] = headerTable[freq][0]else:support_data[frozenset(freq_set)] += headerTable[freq][0]cond_pat_base = self.find_cond_pattern_base(freq, headerTable)  # 寻找到所有条件模式基# 创建条件模式树cond_tree, cur_headtable = self.create_fptree(cond_pat_base, min_support)if cur_headtable != None:self.create_cond_fptree(cur_headtable, min_support, freq_set, freq_items, support_data)  # 递归挖掘条件FP树def generate_L(self, data_set, min_support):data_dic = self.data_compress(data_set)freqItemSet = set()support_data = {}tree_header, headerTable = self.create_fptree(data_dic, min_support, flag=True)  # 创建数据集的fptree# 创建各频繁一项的fptree,并挖掘频繁项并保存支持度计数self.create_cond_fptree(headerTable, min_support, set(), freqItemSet, support_data)max_l = 0for i in freqItemSet:  # 将频繁项根据大小保存到指定的容器L中if len(i) > max_l: max_l = len(i)L = [set() for _ in range(max_l)]for i in freqItemSet:L[len(i) - 1].add(i)for i in range(len(L)):print("frequent item {}:{}".format(i + 1, L[i]))return L, support_datadef generate_R(self, data_set, min_support, min_conf):L, support_data = self.generate_L(data_set, min_support)rule_list = []sub_set_list = []for i in range(0, len(L)):for freq_set in L[i]:for sub_set in sub_set_list:if sub_set.issubset(freq_set) and freq_set - sub_set in support_data:  # and freq_set-sub_set in support_dataconf = support_data[freq_set] / support_data[freq_set - sub_set]big_rule = (freq_set - sub_set, sub_set, conf)if conf >= min_conf and big_rule not in rule_list:rule_list.append(big_rule)sub_set_list.append(freq_set)rule_list = sorted(rule_list, key=lambda x: (x[2]), reverse=True)return rule_listif __name__ == "__main__":begin_time = time.time()min_support = 3  # 最小支持度,不是比率,是出现次数min_conf = 0.2 # 最小置信度data_set = load_data()print(data_set)fp = Fp_growth_plus()rule_list = fp.generate_R(data_set, min_support, min_conf)print("confidence:")show_confidence(rule_list)end_time = time.time()timeget = end_time - begin_timeprint("程序开始时间:",begin_time)print("程序结束时间:",end_time)print("程序花费时间:",timeget)print(u'当前进程的内存使用:%.4f GB' % (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024))
  • 程序运行结果如下:
[['牛奶', '面包'], ['火腿', '牛奶', '面包'], ['可乐', '火腿', '面包'], ['可乐', '方便面', '火腿'], ['可乐', '方便面', '火腿', '面包']]
100%|██████████████████████████████████████████| 5/5 [00:00<00:00, 46294.75it/s]
frequent item 1:{frozenset({'可乐'}), frozenset({'面包'}), frozenset({'火腿'})}
frequent item 2:{frozenset({'火腿', '可乐'}), frozenset({'火腿', '面包'})}
confidence:1     1.000        ['可乐']=>['火腿']2     0.750        ['火腿']=>['可乐']3     0.750        ['火腿']=>['面包']4     0.750        ['面包']=>['火腿']
程序开始时间: 1671694715.27943
程序结束时间: 1671694715.282612
程序花费时间: 0.0031821727752685547
当前进程的内存使用:0.0648 GB
  • 参考文章: Fp-growth算法python实现

关联规则挖掘算法: Aprior算法和Fpgrowth算法相关推荐

  1. 关联规则挖掘(Apriori算法和FP-Growth算法)

    一.关联规则概述 1.关联规则分析用于在一个数据集中找出各种数据项之间的关联关系,广泛用于购物篮数据.个性化推荐.预警.时尚穿搭.生物信息学.医疗诊断.网页挖掘和科学数据分析中 2.关联规则分析又称购 ...

  2. 使用Apriori算法和FP-growth算法进行关联分析

    目录 1. 关联分析 2. Apriori原理 3. 使用Apriori算法来发现频繁集 4. 使用FP-growth算法来高效发现频繁项集 5. 示例:从新闻网站点击流中挖掘新闻报道 扩展阅读 系列 ...

  3. matlab实现prim算法,Prim算法和Kruskal算法的Matlab实现

    Prim算法和Kruskal算法的Matlab实现 <计算机仿真>期末大作业 Prim算法和Kruskal算法的Matlab实现 05605刘禹050697(30) 连线问题应用举例: 欲 ...

  4. 关联分析Apriori算法和FP-growth算法初探

    1. 关联分析是什么? Apriori和FP-growth算法是一种关联算法,属于无监督算法的一种,它们可以自动从数据中挖掘出潜在的关联关系.例如经典的啤酒与尿布的故事.下面我们用一个例子来切入本文对 ...

  5. 【Apriori算法和FP-growth算法】

    Apriori算法 通过例题解析算法思路 1.频繁项集思路描述 通过支持度算出min_sup,进行基础比较,大于min_sup的写入频繁1项集,然后依次写出2项集,直到k项集. 2.强关联解题思路 依 ...

  6. 【Linux进程、线程、任务调度】三 CPU/IO消耗型进程 吞吐率/响应 SCHED_FIFO算法与SCHED_RR算法 SCHED_NORMAL算法和CFS算法 nice与renic chrt

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2(已满): 780902027 学习 ...

  7. pca算法python_PCA算法和python实现

    第十三章 利用PCA来简化数据 一.降维技术 当数据的特征很多的时候,我们把一个特征看做是一维的话,我们数据就有很高的维度.高维数据会带来计算困难等一系列的问题,因此我们需要进行降维.降维的好处有很多 ...

  8. 《OpenCv视觉之眼》Python图像处理十四 :Opencv图像轮廓提取之Scharr算法和Canny算法

    本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...

  9. 最短路径(Dijkstra算法和Floyd算法)

    最短路径 ​ 在图中,不可避免要解决的一个问题就是计算两点之间的最短路径,对于图结构来说,两个点之间不一定只有一条路径,那么如何才能找出最短的那一条就是图中最短路径问题.最短路径问题在实际生活中应用十 ...

最新文章

  1. 百度搜索查询命令——组合型
  2. 怎样搭建Android开发平台(转)
  3. BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会 树形DP + 带权重心
  4. 漫谈边缘计算(三):5G的好拍档
  5. linux分区概念理解,在linux安装中的分区概念(转)
  6. linux下基于Posix message queue的同步消息队列的实现
  7. distinct group by一起用_用ggplot2来画带有对角线的热图。
  8. HDU 1754 I hate it【线段树之单点替换区间最值】
  9. 笔记本我的计算机怎么找不到了,Win10我的电脑在哪?图标没了怎么办?Win10此电脑不见了解决方法...
  10. zabbix4.0LTS安装配置
  11. 简述Java三大特性
  12. ubuntu局域网服务器搭建网站,ubuntu搭建局域网dns服务器
  13. 这游戏全服只有一个玩家,硬是坚挺了18年,官方竟还推新版本?
  14. LTspice中 Voltage Controlled Switches的使用方法
  15. Stm32F4以太网远程固件升级BootLoader踩过官方的坑
  16. java 生成随机编码_Java生成随机编码
  17. 【高项】第3章 项目立项管理【知识点精华笔记】
  18. 关于 VScode 中使用 python 相对路径找不到的问题(解决)
  19. 子网怎么算?IP地址(A,B,C,D,E类地址),子网,子网掩码,容纳主机20台,网络号,主机号
  20. Python多线程顺序运行

热门文章

  1. Matlab车牌识别
  2. 年后想做包工头的,这些技巧你们知道吗?
  3. codeblocks:: frotran 调用dll(详细)
  4. svn 文件前前面的标识符
  5. 视频教程-Java并发编程实战-Java
  6. Dsp28335课程设计
  7. Open-Falcon学习之路(1)
  8. 程序员如何给孩子取名字?
  9. python正则表达式提取电话号码_python正则表达式提取文本中的电话号码和邮箱
  10. 穿透还原卡或还原软件