Apriori 算法分析:
利用my_new_apriori.py文件,对杂货店商品进行关联规则挖掘,支持度=0.06,置信度=0.2
使用的数据集:
数据集下载地址:
链接:https://pan.baidu.com/s/14Vgvv5OK-luwTgoEZozbRw
提取码:vvym
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 22 10:21:02 2019
@author: Administrator
"""
import pandas as pda
import numpy as np
#定义函数data_set装载数据集
def load_data_set():
'''
定义数据集data_set列表:每一个列表中又包含了一些列表,这些列表表示事物数据库中的每一次交易,
每个小列表表示的是每一次交易中所包含的产品项
'''
#读取文件数据,且数据中不包含数据的表头,所以header = None
filename = r'E:\杂货店商品.xlsx'
data_x = pda.read_excel(filename,header = None)#默认打开Sheet1
#用空格将所读取文件中的NaN进行替换
data_x = data_x.fillna('')
#将所得到的的data_x处理成为数组之后再将其类型转换为字符串类型
train_data = np.array(data_x).astype(str)
#再将数组train_data转换为列表赋值给data_set
data_set = train_data.tolist()
#针对数据集中的每一笔交易i进行处理
for i in data_set:
while "" in i:
i.remove("")
return data_set
def create_C1(data_set):
"""
Create frequent candidate 1-itemset C1 by scaning data set.
Args:
data_set: A list of transactions. Each transaction contains several items.
Returns:
C1: A set which contains all frequent candidate 1-itemsets
"""
#定义一个空集合C1
C1 = set()
#针对传入函数的数据集data_set中的每一项事务例如:t = ['l1', 'l2', 'l5']
for t in data_set:
#针对事物数据库中的每一项事务例如:['l1', 'l2', 'l5']中的一个元素item = ’l1‘
for item in t:
'''
由于要使用字典(support_data)记录项集的支持度,需要用项集作为key,
而可变集合无法作为字典的key,因此在这里应将项集转为固定集合frozenset
'''
item_set = frozenset([item])
#将上一步所得到的item_set加入到集合C1里面
C1.add(item_set)
'''
因为集合中是不可能产生重复元素的,所以C1最后得到的结果集就是C1(l1,l2,l3,l4,l5)
这样就得到了事务数据库中的一阶候选项集
'''
return C1
#利用函数is_apriori和k-1阶的频繁项集对所得到的的一个个k阶候选项集Ck_item进行剪枝
def is_apriori(Ck_item, Lksub1):
"""
Judge whether a frequent candidate k-itemset satisfy Apriori property.
Args:
Ck_item: a frequent candidate k-itemset in Ck which contains all frequent
candidate k-itemsets.
Lksub1: Lk-1, a set which contains all frequent candidate (k-1)-itemsets.
Returns:
True: satisfying Apriori property.
False: Not satisfying Apriori property.
"""
#扫描函数create_Ck中所传过来的参数Ck_item中的每一个元素
for item in Ck_item:
#从Ck_item依次减去Ck_item中的一个元素并赋值给sub_Ck
sub_Ck = Ck_item - frozenset([item])
#然后判断sub_Ck是否是k-1阶频繁项集的子集,如果是返回True,否则返回False
if sub_Ck not in Lksub1:
return False
return True
#create_Ck函数通过对Lk-1阶频繁项集自连接产生k阶候选项集
def create_Ck(Lksub1, k):
"""
Create Ck, a set which contains all all frequent candidate k-itemsets
by Lk-1's own connection operation.
Args:
Lksub1: Lk-1, a set which contains all frequent candidate (k-1)-itemsets.
k: the item number of a frequent itemset.
Return:
Ck: a set which contains all all frequent candidate k-itemsets.
"""
#定义一个空集合Ck用来存放Lk-1阶频繁项集自连接产生k阶候选项集
Ck = set()
#计算Lk-1阶频繁项集集合的长度
len_Lksub1 = len(Lksub1)
#将Lk-1阶频繁项集Lksub1转换为列表list_Lksub1
list_Lksub1 = list(Lksub1)
#针对列表list_Lksub1中的第i个元素
for i in range(len_Lksub1):
#针对列表list_Lksub1中的第j个元素
for j in range(1, len_Lksub1):
#将列表中的第i个元素和第j个元素分表转换为列表l1和l2
l1 = list(list_Lksub1[i])
l2 = list(list_Lksub1[j])
#对列表l1和l2进行排序
l1.sort()
l2.sort()
#针对排序好后的列表l1和l2,判断他们的第0:k-2元素是否相等
if l1[0:k-2] == l2[0:k-2]:
'''
注意:这里如果是由一阶频繁项集产生二阶候选项集时:k=2,则l1[0:k-2] == l2[0:k-2]为
l1[0:0] == l2[0:0]因为他们是空的所以他们始终为ture,就可以由1阶频繁项集自连接
产生二阶候选项集
如果相等,则他们进行自连接得到一个列表Ck_item
'''
# '|'表示的是联合:两个集合的联合是一个新集合,该集合中的每个元素都至少是其中一个集合的成员
# 即属于两个集合其中之一的成员,联合符号有一个等价的方法union()
Ck_item = list_Lksub1[i] | list_Lksub1[j]
#判断是否满足函数is_apriori,如果满足则将得到的一个个k阶候选项集添加到集合Ck中
if is_apriori(Ck_item, Lksub1):
Ck.add(Ck_item)
#返回所得到的k阶候选大项集
return Ck
'''
generate_Lk_by_Ck:根据所传入的交易数据data_set,Ck是我们在函数create_C1所产生的候选项集
min_support、support_data分别是最小支持数和所用来记录频繁项集的支持数定义的字典
这个函数主要是通过所传入的参数,由一阶候选项集产生一阶频繁项集并返回
'''
def generate_Lk_by_Ck(data_set, Ck, min_support, support_data):
"""
Generate Lk by executing a delete policy from Ck.
Args:
data_set: A list of transactions. Each transaction contains several items.
Ck: A set which contains all all frequent candidate k-itemsets.
min_support: The minimum support.
support_data: A dictionary. The key is frequent itemset and the value is support.
Returns:
Lk: A set which contains all all frequent k-itemsets.
"""
#定义一个空集合LK用来存放所产生的频繁项集
Lk = set()
#定义一个空字典item_count来存放所产生的候选项集的支持数
item_count = {}
#对整个事务数据库进行扫描t = ['l1', 'l2', 'l5']
for t in data_set:
#针对候选项集Ck进行扫描 item = 'l1',item = l2,item = l3...等
for item in Ck:
#判断候选项集Ck中的item是否存在于事务数据库的一项事务中的一个子集
if item.issubset(t):
#判断它是否已经存在字典item_count中
if item not in item_count:
#如果不存在字典中,则表示它是第一次出现在字典中,它相应的value为1
item_count[item] = 1
else:
#否则它相应value就加1,
item_count[item] += 1
#t_num表示的是整个事务数据库中总共有几项事务
t_num = float(len(data_set))
#扫描所得到的字典中的数据
for item in item_count:
'''
item_count[item] / t_num表示的是对应item所对应的支持度
判断所得到的的item的支持度是否大于最小支持度,
'''
if (item_count[item] / t_num) >= min_support:
#如果item的支持度大于最小支持度,那么就把它加到集合Lk当中
Lk.add(item)
#并且将item和对应的item的支持度加入到support_data字典中
#support_data中的key为对应的item,value为item中对应最小支持度
support_data[item] = item_count[item] / t_num
#将所得到的频繁项集加入到集合Lk中
return Lk
def generate_L(data_set, k, min_support):
"""
Generate all frequent itemsets.
Args:
data_set: A list of transactions. Each transaction contains several items.
k: Maximum number of items for all frequent itemsets.
min_support: The minimum support.
Returns:
L: The list of Lk.
support_data: A dictionary. The key is frequent itemset and the value is support.
"""
#定义一个空字典,用来记录频繁项集的支持数,key为各自的频繁项集,value为各自频繁项集的支持数
support_data = {}
#调用函数create_C1传入数据集data_set并赋值给C1
C1 = create_C1(data_set)
'''
由C1得到的一阶候选项集产生一阶频繁项集
然后调用函数generate_Lk_by_Ck产生一阶频繁项集,函数所传入的参数分别有:
1.data_set:所传入的数据集
2.C1:由函数create_C1所产生的一阶候选项集
3.min_support、support_data分别是最小支持数和所用来记录频繁项集的支持数定义的字典
然后调用函数generate_Lk_by_Ck
'''
#将函数generate_Lk_by_Ck所得到的频繁项集赋值给L1
L1 = generate_Lk_by_Ck(data_set, C1, min_support, support_data)
#对频繁项集L1进行复制到 Lksub1
Lksub1 = L1.copy()
#定义一个空的列表L用来存放所产生的频繁项集
L = []
#将Lksub1加入到列表L中,一阶频繁项集集合作为列表L中的一个元素
L.append(Lksub1)
for i in range(2, k+1):
#上面我们得到了一阶频繁项集并作为列表L一个元素并加到了列表L中
#接下来将依次扫描事务数据库中的数据利用函数create_Ck使得Lk-1阶频繁项集自连接得到K阶候选项集Ci,
Ci = create_Ck(Lksub1, i)
#将得到的2到k阶的候选项集利用函数generate_Lk_by_Ck依次产生2到k阶的频繁项集Li
Li = generate_Lk_by_Ck(data_set, Ci, min_support, support_data)
#对频繁项集Li进行复制到 Lksubi
Lksub1 = Li.copy()
#将Lksubi加入到列表L中,i阶频繁项集集合作为列表L中的一个元素
L.append(Lksub1)
#将所得到的K阶频繁项集所组成的列表L和存放元素item和item对应的支持数的字典support_data进行返回
return L, support_data
'''
将由函数generate_L产生的K阶频繁项集所组成的列表L和存放元素item和item对应的支持数的字典support_data
的数据利用函数generate_big_rules计算他们之间的强关联规则
'''
def generate_big_rules(L, support_data, min_conf):
"""
Generate big rules from frequent itemsets.
Args:
L: The list of Lk.得到的K阶频繁项集所组成的列表L
support_data: A dictionary. The key is frequent itemset and the value is support.
存放元素item和item对应的支持数的字典support_data
min_conf: Minimal confidence.最小置信度
Returns:
big_rule_list: A list which contains all big rules. Each big rule is represented
as a 3-tuple.强关联规则所产生的的列表big_rule_list
"""
#定义空列表big_rule_list用来存放所产生的强关联规则数据
big_rule_list = []
#定义空列表sub_set_list用来存放频繁项集
sub_set_list = []
#扫描所得到的K阶频繁项集所组成的列表L,这里分别是1阶、2阶、3阶频繁项集三个元素(三个集合)
#针对列表L中的每一个集合,这里的i从0-len(L)
for i in range(0, len(L)):
#针对列表L中的每一个集合freq_set
for freq_set in L[i]:
#第一轮循环加入一阶频繁项集到sub_set_list列表中,
#第二轮循环就利用二阶频繁项集和sub_set_list里面的一阶频繁项集产生关联规则
for sub_set in sub_set_list:
#issubset() 方法用于判断集合的所有元素是否都包含在指定集合中,是返回True,否则返回False;
#判断集合sub_set是否为集合freq_set的子集
if sub_set.issubset(freq_set):
#计算集合freq_set=>freq_set-sub_set的置信度赋值给conf
conf = support_data[freq_set] / support_data[freq_set - sub_set]
big_rule = (freq_set - sub_set, sub_set, conf)
#判断列表中所生成的强关联规则列表big_rule_list中没有所产生关联规则的big_rule这一条数据
#并且这一组数据的置信度大于最小置信度;
if conf >= min_conf and big_rule not in big_rule_list:
# print freq_set-sub_set, " => ", sub_set, "conf: ", conf
#满足上述条件就将其作为一组强关联规则的数据加入到big_rule_list
big_rule_list.append(big_rule)
sub_set_list.append(freq_set)
#返回强关联规则所产生的的列表big_rule_list
return big_rule_list
#主函数
if __name__ == "__main__":
"""
Test
"""
#把load_data_set()函数得到的列表集合赋值给data_set这个变量
data_set = load_data_set()
'''
调用generate_L函数生成L阶的频繁项
generate_L函数有两个返回值,分别是:
1.L:存放由事物数据库所有产生的频繁项集
2.support_data:generate_L函数中所定义的一个字典,用来记录项集的支持度
generate_L函数有三个参数,分别是:
1.data_set表示所使用的数据集<所传入的交易数据库>
2.k表示由数据集data_set所能产生的数据集的阶数
3.min_support表示的是数据集的最小支持度的阈值
'''
L, support_data = generate_L(data_set, k=3, min_support=0.06)
'''
将由函数generate_L产生的K阶频繁项集所组成的列表L和存放元素item和item对应的支持数的字典support_data
的数据利用函数generate_big_rules得到他们之间的强关联规则存入big_rules_list
'''
big_rules_list = generate_big_rules(L, support_data, min_conf=0.2)
#针对列表L中的各个集合Lk,打印输出所得到的频繁项集L
for Lk in L:
print( "="*50)
#str(len(list(Lk)[0]))表示列表L中各个集合Lk中的几阶元素并将其转换为字符串类型
print( "frequent " + str(len(list(Lk)[0])) + "-itemsets\t\tsupport")
print ("="*50)
for freq_set in Lk:
#分别打印输出str(len(list(Lk)[0]))阶元素freq_set以及他所对应的支持度
print( freq_set, support_data[freq_set])
print()
print( "Big Rules")
#针对所得到的强关联规则的各个集合的映射关系
for item in big_rules_list:
#打印输出所满足的强关联规则中各个集合之间的映射关系以及他们之间的置信度
priAAAAnt( item[0], "=>", item[1], "conf: ", item[2])