实验六、数据挖掘之关联分析

一、实验目的

1. 理解Apriori算法的基本原理

2. 理解FP增长算法的基本原理

3. 学会用python实现Apriori算法

4. 学会用python实现FP增长算法

二、实验工具

1. Anaconda

2. sklearn

3. Pandas

三、实验简介

Apriori算法在发现关联规则领域具有很大影响力。算法命名源于算法使用了频繁项集性质的先验(prior)知识。在具体实验时,Apriori算法将发现关联规则的过程分为两个步骤:第一步通过迭代,检索出事务数据库中的所有频繁项集,即支持度不低于用户设定的阈值的项集;第二步利用频繁项集构造出满足用户最小信任度的规则。其中,挖掘或识别出所有频繁项集是该算法的核心,占整个计算量的大部分。

在对深度优先数据挖掘算法的研究工作中,Han等人没有采用潜在频繁项集的方法求解频繁项集,而是提出了称为频率模式增长(FP_growth)的算法。该算法通过扫描数据库创建FP_tree的根节点并标示为null,对数据库D中的每一个事务Tran,按L中的次序对Tran中的频繁项排序,设Tran中排序后的频繁项列表[p|P],这里p是第一个元素,P是保留列表。接着调用函数insert_tree([p|P],T),如果树T有一个子节点N且N.item_name=p.item_name,就将N节点计数加1;否则就创建一个新节点N,设计数为1,它的父节点连接到T,节点连接到同名的节点连接结构上。如果P是非空的,就递归调用insert_tree(P,N)。由于压缩了数据库内容,并且在将频繁项写入FP_tree结构时,保留了项集间的相连信息。求解频繁项集的问题,就转化为递归地找出最短频繁模式并连接其后缀构成长频繁模式的问题。

四、实验内容

1. 利用python语言编写Apriori算法,挖掘出下表中数据集的频繁项集,最小支持度为30%。

# -*- coding: utf-8 -*-
"""
Created on Fri May 20 20:25:24 2022@author: zhenkai
"""def load_data_set():data_set = [['a','b','d','e'], ['b', 'c', 'd'], ['a','b','d','e'],['a','b','d','e'],['a','b','d','e'],['b', 'd', 'e'], ['c', 'd'], ['a', 'b', 'c'], ['a', 'd', 'e'], ['b', 'd']] return data_set
''' 参数:数据库事务集 '''
def Create_C1(data_set):C1 = set() for t in data_set:for item in t: item_set = frozenset([item])# 为生成频繁项目集时扫描数据库时以提供issubset()功能C1.add(item_set)return C1
''' 参数:候选频繁k项集,频繁k-1项集 '''
def is_apriori(Ck_item, Lk_sub_1): for item in Ck_item: sub_item = Ck_item - frozenset([item]) if sub_item not in Lk_sub_1: return False return True
''' # 参数:频繁k-1项集,当前要生成的候选频繁几项集 '''
def Create_Ck(Lk_sub_1, k):Ck = set() len_Lk_sub_1 = len(Lk_sub_1) list_Lk_sub_1 = list(Lk_sub_1) for i in range(len_Lk_sub_1): #i: [0, len_Lk_sub_1)for j in range(i+1, len_Lk_sub_1):#j: [i+1, len_Lk_sub_1)l1 = list(list_Lk_sub_1[i])l2 = list(list_Lk_sub_1[j])l1.sort()l2.sort()# list[s:t]:截取s到t范围的元素生成一个新list if l1[0:k-2] == l2[0:k-2]:# 判断l1的前k-1-1个元素与l2的前k-1-1个元素对应位是否全部相同 Ck_item = list_Lk_sub_1[i] | list_Lk_sub_1[j] if is_apriori(Ck_item, Lk_sub_1): Ck.add(Ck_item) return Ck
''' 参数:数据库事务集,候选频繁k项集,最小支持度,项目集-支持度dic '''
def Generate_Lk_By_Ck(data_set, Ck, min_support, support_data): Lk = set() # 通过dic记录候选频繁k项集的事务支持个数 item_count = {} for t in data_set: for Ck_item in Ck: if Ck_item.issubset(t): if Ck_item not in item_count: item_count[Ck_item] = 1 else: item_count[Ck_item] += 1 data_num = float(len(data_set)) for item in item_count: if(item_count[item] / data_num) >= min_support: Lk.add(item) support_data[item] = item_count[item] / data_num return Lk
''' 参数:数据库事务集,求的最高项目集为k项,最小支持度 '''
def Generate_L(data_set, max_k, min_support): # 创建一个频繁项目集为key,其支持度为value的dic support_data = {} C1 = Create_C1(data_set) L1 = Generate_Lk_By_Ck(data_set, C1, min_support, support_data) Lk_sub_1 = L1.copy() # 对L1进行浅copy L = []L.append(Lk_sub_1)# 末尾添加指定元素 for k in range(2, max_k+1): Ck = Create_Ck(Lk_sub_1, k) Lk = Generate_Lk_By_Ck(data_set, Ck, min_support, support_data) Lk_sub_1 = Lk.copy() L.append(Lk_sub_1) return L, support_data
''' 参数:所有的频繁项目集,项目集-支持度dic,最小置信度 '''
def Generate_Rule(L, support_data, min_confidence): rule_list = [] sub_set_list = [] for i in range(len(L)): for frequent_set in L[i]: for sub_set in sub_set_list: if sub_set.issubset(frequent_set): conf = support_data[frequent_set] / support_data[sub_set] # 将rule声明为tuple rule = (sub_set, frequent_set-sub_set, conf) if conf >= min_confidence and rule not in rule_list: rule_list.append(rule) sub_set_list.append(frequent_set) return rule_list
if __name__ == "__main__": data_set = load_data_set() L, support_data = Generate_L(data_set, 4, 0.3)#最小支持度是30% rule_list = Generate_Rule(L, support_data, 0.7)for Lk in L: print("="*55) print("frequent " + str(len(list(Lk)[0])) + "-itemsets\t\tsupport")print("="*55) for frequent_set in Lk: print(frequent_set,"\t\t", support_data[frequent_set]) print()print("Rules") for item in rule_list: print(item[0], "=>", item[1], "'s conf: ", item[2])

将rule注释掉后的运行结果

将rule打印出的部分截图

2. (选做)利用python语言编写FP增长算法,挖掘出上表中数据集的频繁项集,最小支持度为30%。

#2、FP树增长算法发现频繁项集from collections import defaultdict, Counter, deque
import math
import copyclass node:def __init__(self, item, count, parent):  # 本程序将节点之间的链接信息存储到项头表中,后续可遍历项头表添加该属性self.item = item  # 该节点的项self.count = count  # 项的计数self.parent = parent  # 该节点父节点的idself.children = []  # 该节点的子节点的listclass FP:def __init__(self, minsup=0.5):self.minsup = minsupself.minsup_num = None  # 支持度计数self.N = Noneself.item_head = defaultdict(list)  # 项头表self.fre_one_itemset = defaultdict(lambda: 0)  # 频繁一项集,值为支持度self.sort_rules = None  # 项头表中的项排序规则,按照支持度从大到小有序排列self.tree = defaultdict()  # fp树, 键为节点的id, 值为nodeself.max_node_id = 0  # 当前树中最大的node_id, 用于插入新节点时,新建node_idself.fre_itemsets = []  # 频繁项集self.fre_itemsets_sups = []  # 频繁项集的支持度计数def init_param(self, data):self.N = len(data)self.minsup_num = math.ceil(self.minsup * self.N)self.get_fre_one_itemset(data)self.build_tree(data)returndef get_fre_one_itemset(self, data):# 获取频繁1项,并排序,第一次扫描数据集c = Counter()for t in data:c += Counter(t)for key, val in c.items():if val >= self.minsup_num:self.fre_one_itemset[key] = valsort_keys = sorted(self.fre_one_itemset, key=self.fre_one_itemset.get, reverse=True)self.sort_rules = {k: i for i, k in enumerate(sort_keys)}  # 频繁一项按照支持度降低的顺序排列,构建排序规则returndef insert_item(self, parent, item):# 将事务中的项插入到FP树中,并返回插入节点的idchildren = self.tree[parent].childrenfor child_id in children:child_node = self.tree[child_id]if child_node.item == item:self.tree[child_id].count += 1next_node_id = child_idbreakelse:  # 循环正常结束,表明当前父节点的子节点中没有项与之匹配,所以新建子节点,更新项头表和树self.max_node_id += 1next_node_id = copy.copy(self.max_node_id)  # 注意self.max_node_id 是可变的,引用时需要copyself.tree[next_node_id] = node(item=item, count=1, parent=parent)  # 更新树,添加节点self.tree[parent].children.append(next_node_id)  # 更新父节点的孩子列表self.item_head[item].append(next_node_id)  # 更新项头表return next_node_iddef build_tree(self, data):# 构建项头表以及FP树, 第二次扫描数据集one_itemset = set(self.fre_one_itemset.keys())self.tree[0] = node(item=None, count=0, parent=-1)for t in data:t = list(set(t) & one_itemset)  # 去除该事务中非频繁项if len(t) > 0:t = sorted(t, key=lambda x: self.sort_rules[x])  # 按照项的频繁程度从大到小排序parent = 0  # 每个事务都是从树根开始插起for item in t:parent = self.insert_item(parent, item)  # 将排序后的事务中每个项依次插入FP树returndef get_path(self, pre_tree, condition_tree, node_id, suffix_items_count):# 根据后缀的某个叶节点的父节点出发,选取出路径,并更新计数。suffix_item_count为后缀的计数if node_id == 0:returnelse:if node_id not in condition_tree.keys():current_node = copy.deepcopy(pre_tree[node_id])current_node.count = suffix_items_count  # 更新计数condition_tree[node_id] = current_nodeelse:  # 若叶节点有多个,则路径可能有重复,计数叠加condition_tree[node_id].count += suffix_items_countnode_id = condition_tree[node_id].parentself.get_path(pre_tree, condition_tree, node_id, suffix_items_count)  # 递归构建路径returndef get_condition_tree(self, pre_tree, suffix_items_ids):# 构建后缀为一个项的条件模式基。可能对应多个叶节点,综合后缀的各个叶节点的路径condition_tree = defaultdict()  # 字典存储条件FP树,值为父节点for suffix_id in suffix_items_ids:  # 从各个后缀叶节点出发,综合各条路径形成条件FP树suffix_items_count = copy.copy(pre_tree[suffix_id].count)  # 叶节点计数node_id = pre_tree[suffix_id].parent  # 注意条件FP树不包括后缀if node_id == 0:continueself.get_path(pre_tree, condition_tree, node_id, suffix_items_count)return condition_treedef extract_suffix_set(self, condition_tree, suffix_items):# 根据条件模式基,提取频繁项集, suffix_item为该条件模式基对应的后缀# 返回新的后缀,以及新添加项(将作为下轮的叶节点)的idnew_suffix_items_list = []  # 后缀中添加的新项new_item_head = defaultdict(list)  # 基于当前的条件FP树,更新项头表, 新添加的后缀项item_sup_dict = defaultdict(int)for key, val in condition_tree.items():item_sup_dict[val.item] += val.count  # 对项出现次数进行统计new_item_head[val.item].append(key)for item, sup in item_sup_dict.items():if sup >= self.minsup_num:  # 若条件FP树中某个项是频繁的,则添加到后缀中current_item_set = [item] + suffix_itemsself.fre_itemsets.append(current_item_set)self.fre_itemsets_sups.append(sup)new_suffix_items_list.append(current_item_set)else:new_item_head.pop(item)return new_suffix_items_list, new_item_head.values()def get_fre_set(self, data):# 构建以每个频繁1项为后缀的频繁项集self.init_param(data)suffix_items_list = []suffix_items_id_list = []for key, val in self.fre_one_itemset.items():suffix_items = [key]suffix_items_list.append(suffix_items)suffix_items_id_list.append(self.item_head[key])self.fre_itemsets.append(suffix_items)self.fre_itemsets_sups.append(val)pre_tree = copy.deepcopy(self.tree)  # pre_tree 是尚未去除任何后缀的前驱,若其叶节点的项有多种,则可以形成多种条件FP树self.dfs_search(pre_tree, suffix_items_list, suffix_items_id_list)returndef bfs_search(self, pre_tree, suffix_items_list, suffix_items_id_list):# 宽度优先,递增构建频繁k项集q = deque()q.appendleft((pre_tree, suffix_items_list, suffix_items_id_list))while len(q) > 0:param_tuple = q.pop()pre_tree = param_tuple[0]for suffix_items, suffix_items_ids in zip(param_tuple[1], param_tuple[2]):condition_tree = self.get_condition_tree(pre_tree, suffix_items_ids)new_suffix_items_list, new_suffix_items_id_list = self.extract_suffix_set(condition_tree, suffix_items)if new_suffix_items_list:q.appendleft((condition_tree, new_suffix_items_list, new_suffix_items_id_list))  # 储存前驱,以及产生该前驱的后缀的信息returndef dfs_search(self, pre_tree, suffix_items_list, suffix_items_id_list):# 深度优先,递归构建以某个项为后缀的频繁k项集for suffix_items, suffix_items_ids in zip(suffix_items_list, suffix_items_id_list):condition_tree = self.get_condition_tree(pre_tree, suffix_items_ids)new_suffix_items_list, new_suffix_items_id_list = self.extract_suffix_set(condition_tree, suffix_items)if new_suffix_items_list:  # 如果后缀有新的项添加进来,则继续深度搜索self.dfs_search(condition_tree, new_suffix_items_list, new_suffix_items_id_list)returnif __name__ == '__main__':data2 = [list('abde'), list('bcd'), list('acde'), list('abde'), list('bcde'),list('bde'), list('cd')]fp = FP(minsup=3/7)fp.get_fre_set(data2)for itemset, sup in zip(fp.fre_itemsets, fp.fre_itemsets_sups):print(itemset, sup)

运行结果

五、实验总结(写出本次实验的收获,遇到的问题等)

通过本次的实验,了解了对频繁项级的处理,通过Apriori算法实现,理解了Apriori算法将发现关联规则的过程分为两个步骤:第一步通过迭代,检索出事务数据库中的所有频繁项集;第二步利用频繁项集构造出满足用户最小信任度的规则。重要的是要挖掘或识别出所有频繁项集。

实验六、数据挖掘之关联分析相关推荐

  1. 数据挖掘之关联分析(实验展示以及源代码)

    数据挖掘之关联分析 算法实现:Apriori算法和FP-growth 算法 源代码 简单描述下,关联分析概念 关联分析概念主要参考下面的博文 原文:https://blog.csdn.net/qq_4 ...

  2. 轻松入门机器学习数据挖掘算法——关联分析(Apriori算法)

    小故事:20世纪90年代,沃尔玛超市在对顾客的购物记录进行购物篮分析时,发现了一个奇怪的现象: "啤酒"和"尿布"两件看上去毫无关系的商品,经常出现在同一个购物 ...

  3. 数据挖掘之关联分析Apriori算法

    文章目录 一.理论知识 1.1.定义 1.2.关联规则 1.3.频繁项集的产生 二.python实战 一.理论知识 许多商业企业在运营中积累了大量的数据.例如:普通超市的收银台每天都会收集到大量的用户 ...

  4. 数据挖掘之关联分析七(非频繁模式)

    非频繁模式 非频繁模式,是一个项集或规则,其支持度小于阈值minsup. 绝大部分的频繁模式不是令人感兴趣的,但其中有些分析是有用的,特别是涉及到数据中的负相关时,如一起购买DVD的顾客多半不会购买V ...

  5. 数据挖掘之关联分析四(连续属性处理)

    处理连续属性 挖掘连续属性可能揭示数据的内在联系,包含连续属性的关联规则通常称作量化关联规则(quantitative association rule). 主要讨论三种对连续数据进行关联分析的方法 ...

  6. 数据挖掘之关联分析一(基本概念)

    许多商业企业运营中的大量数据,通常称为购物篮事务(market basket transaction).表中每一行对应一个事务,包含一个唯一标识TID. 利用关联分析的方法可以发现联系如关联规则或频繁 ...

  7. 【数据挖掘】关联分析之先验(Apriori)原理与Apriori算法

    阅读本文之前建议先理解关联分析的基本概念与术语.传送门 本文简单介绍关联分析中的先验(Apriori)原理与Apriori算法,持续更新与补充. 先验(Apriori)原理 原理简介: 如果一个项集是 ...

  8. 数据挖掘之关联分析六(子图模式)

    子图模式 频繁子图挖掘(frequent subgraph mining):在图的集合中发现一组公共子结构. 图和子图 图是一种用来表示实体集之间联系的数据结构. 子图,图       是另一个图   ...

  9. 数据挖掘之关联分析五(序列模式)

    购物篮数据常常包含关于商品何时被顾客购买的时间信息,可以使用这种信息,将顾客在一段时间内的购物拼接成事务序列,这些事务通常基于时间或空间的先后次序. 问题描述 一般地,序列是元素(element)的有 ...

最新文章

  1. Android自定义组合控件
  2. java - 判断 字符串是否为空
  3. VC++使用MCI播放音频文件
  4. python如何在官网下载1005无标题,如何安装python cairo?
  5. VisualStudioCode 中设置中文语言【图文教程】
  6. 内容流量管理的关键技术:多任务保量优化算法实践
  7. 单片机低功耗设计杂谈
  8. 11 父子组件数据关系与状态提升
  9. 调用未绑定的父类方法和使用supper 函数 之间的选择.
  10. 第 2 章 设计模式七大原则
  11. 利用对象字面量创建对象
  12. C加载JVM崩溃,一般是因为某个变量为NULL
  13. ARC下还会存在内存泄露吗?
  14. 程序分析-Joern工具工作流程分析
  15. 基于JAVA传统文化知识竞赛系统计算机毕业设计源码+系统+数据库+lw文档+部署
  16. 计算机绘图图框实验报告,制图基础及计算机绘图实验报告.doc
  17. java 1603,win10系统安装软件提示功能传送错误1603的处理方法
  18. sklearn聚类算法实现
  19. zz成人笑话四级考试(绝对经典)
  20. 如何使用Erdas进行去霾处理

热门文章

  1. STM32——MG90S数字舵机驱动
  2. 计算机显卡有辐射吗,电脑的显卡辐射大吗
  3. WinPE装到硬盘上只需两步——绿色软件下么
  4. 【第三趴】uni-app页面搭建与路由配置(了解工程目录结构、学会搭建页面、配置路由并成功运行)
  5. 火狐浏览器webdriver下载
  6. 常见的个人电脑入侵方式
  7. 唉,江湖阅历不够,在接洽一个S5PV210 wince 项目的时候被一个贱人给骗了
  8. 客户关系应该如何管理?
  9. C++详解:枚举类型 --- enum | Xunlan_blog
  10. 2021-04-21爬虫爬取b站直播间弹幕并制作词云