数据挖掘Apriori算法C++实现
关联规则apriori算法代码

关联规则apriori算法代码Apriori算法是数据挖掘中的一种常用算法,用于挖掘数据集中的频繁项集以及关联规则。
它是由Rakesh Agrawal和Ramakrishnan Srikant在其1994年发表的论文“Fast Algorithms for Mining Association Rules”中提出的。
Apriori Algorithm的思想非常简单,基本思路是:如果一个项集是频繁项集,那么其所有的子集一定都是频繁项集。
关联规则表示属性之间的依赖与关系,可以用来进行业务决策和推荐系统服务。
下面给出Apriori算法的Python实现代码。
1. 实现项集的生成项集(itemset)是指一个或多个项(item)组成的集合。
一个项集中的项可以是物品、服务、事件、属性、特征等等。
在关联规则中,一个项集一般表示一种物品的集合,例如购买“牛奶”、“面包”、“可乐”等等。
为了实现Apriori算法,首先需要实现项集的生成。
项集的生成就是将大小为k-1的频繁项集合并成大小为k的候选项集。
具体实现如下:```def apriori_gen(freq_itemsets, k):# 合并大小为k-1的频繁项集candidates = []n = len(freq_itemsets)for i in range(n):for j in range(i+1, n):# 取出前k-2个项,检查是否相同,如果相同则合并L1 = list(freq_itemsets[i])[:k-2]L2 = list(freq_itemsets[j])[:k-2]L1.sort()L2.sort()if L1 == L2:candidates.append(freq_itemsets[i] | freq_itemsets[j])return candidates```频繁项集(frequent itemset)是指支持度达到阈值的项集。
数据挖掘在信贷风险中的应用——Apriori算法实现

■ 【术用 黎 技应 】
数 据 挖 掘 在 信 贷 风 险 中 的应 用
徐 汉 文
( 东省潮州市技工学校 广 广东 潮州 5 14 ) 2 0 1
摘
要 : 数据挖掘 是从 大量数据 中挖掘 出隐含 的、未知 的、用户可能感 兴趣 的和对 决策者有潜在 价值的知识 和规则 。这 些规则蕴涵 了数据库 中一组 对象之间
f rn OnR w 1 :+ ) o (- :<o []n +
{. . …・
fr(= :< :_) o j0 j2 j+
… …
sp 1[]= : i f []n+ 1
\ \
/
\ \
/
frn 0n Rw 1 ;4) o (= ;(o []1- 1+
i (o []=) fRw 1= 0
/求频 繁 1 项集 { / /统 计支 持数 ¥
f r i0i io :+) o (= : < R w i + f r(= : < C l j + o j 0j io :+) fr kO k io :+) o (= : < C l k +
/ 按支 持数 修剪 ,得 到频繁 l 集} { 项 /
返 回2 / *
… …
/如 果 找 到 的频繁 项 集 数量 是 0则 返 回0 , ,否 则
( ) {,,, ) a AB cD 的项 目集 的格结 构 图 卜1 向下 封 闭
( ) AD b C 的子集
)
3 )频 繁K 集 的产 生原 理 与2 集 的原 理一 样 ,所 以使 用 递归 的 原理 项 项
一
定 是小 的 。用 图 卜 1a中 的格 来展 示这 种重 要 的性 质 。在这 个例 子 中有 ()
频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比(Python实现)

频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对⽐(Python实现)最近上数据挖掘的课程,其中学习到了频繁模式挖掘这⼀章,这章介绍了三种算法,Apriori、FP-Growth和Eclat算法;由于对于不同的数据来说,这三种算法的表现不同,所以我们本次就对这三种算法在不同情况下的效率进⾏对⽐。
从⽽得出适合相应算法的情况。
GitHub:(⼀)算法原理其中相应的算法原理在之前的博客中都有⾮常详细的介绍,这⾥就不再赘述,这⾥给出三种算法⼤概的介绍但是这⾥给出每个算法的关键点:1.1 Apriori算法:限制候选产⽣发现频繁项集重要性质:频繁项集所有⾮空⼦集也⼀定是频繁的。
主要步骤:1. 连接2. 剪枝特点:需要多次扫描数据库,对于⼤规模数据效率很低!1.2 FP-Growth算法通过模式增长挖掘频繁模式主要步骤:1. 构建频繁模式树2. 构造条件模式基3. 挖掘频繁模式特点:两次扫描数据库,采⽤分治的策略有效降低搜索开销1.3 Eclat算法使⽤垂直格式挖掘频繁项集主要步骤:1. 将数据倒排{ item:TID_set }2. 通过求频繁k项集的交集来获取k+1项集特点:仅需要⼀次扫描数据库,TID集合很长的话需要消耗⼤量的内存和计算时间(⼆)算法实现由于各个博客给出的算法实现并不统⼀,⽽且本⼈在实现《机器学习实战》中FP-Growth算法的时候发现,在在创建FP-Tree时根据headTable中元素的⽀持度顺序的排序过程中,这个地⽅的排序⽅法写的有问题,当在模式稠密时,具有很多⽀持度相同的项集,书中的代码并没有考虑着⼀点,所以如果遇到⽀持度相同的项集那个就会出现⼀定的随机性,导致建树过程出错,最后的频繁项集结果会偏⼩,因此这⾥对改错误进⾏了纠正,在⽀持度相同时,添加了按照项集排序的规则,这样建⽴的FP-Tree才完全正确。
1.1 Apriori算法实现:1# -*- coding: utf-8 -*-2'''3@author: Infaraway4@time: 2017/4/15 12:545@Function:6'''789def init_c1(data_set_dict, min_support):10 c1 = []11 freq_dic = {}12for trans in data_set_dict:13for item in trans:14 freq_dic[item] = freq_dic.get(item, 0) + data_set_dict[trans]15# 优化初始的集合,使不满⾜最⼩⽀持度的直接排除16 c1 = [[k] for (k, v) in freq_dic.iteritems() if v >= min_support]17 c1.sort()18return map(frozenset, c1)192021def scan_data(data_set, ck, min_support, freq_items):22"""23计算Ck中的项在数据集合中的⽀持度,剪枝过程24 :param data_set:25 :param ck:26 :param min_support: 最⼩⽀持度27 :param freq_items: 存储满⾜⽀持度的频繁项集28 :return:29"""30 ss_cnt = {}31# 每次遍历全体数据集32for trans in data_set:33for item in ck:34# 对每⼀个候选项集,检查是否是 term中的⼀部分(⼦集),即候选项能否得到⽀持35if item.issubset(trans):36 ss_cnt[item] = ss_cnt.get(item, 0) + 137 ret_list = []38for key in ss_cnt:39 support = ss_cnt[key] # 每个项的⽀持度40if support >= min_support:41 ret_list.insert(0, key) # 将满⾜最⼩⽀持度的项存⼊集合42 freq_items[key] = support #43return ret_list444546def apriori_gen(lk, k):47"""48由Lk的频繁项集⽣成新的候选项集连接过程49 :param lk: 频繁项集集合50 :param k: k 表⽰集合中所含的元素个数51 :return: 候选项集集合52"""53 ret_list = []54for i in range(len(lk)):55for j in range(i+1, len(lk)):56 l1 = list(lk[i])[:k-2]57 l2 = list(lk[j])[:k-2]58 l1.sort()59 l2.sort()60if l1 == l2:61 ret_list.append(lk[i] | lk[j]) # 求并集62# retList.sort()63return ret_list646566def apriori_zc(data_set, data_set_dict, min_support=5):67"""68 Apriori算法过程69 :param data_set: 数据集70 :param min_support: 最⼩⽀持度,默认值 0.571 :return:72"""73 c1 = init_c1(data_set_dict, min_support)74 data = map(set, data_set) # 将dataSet集合化,以满⾜scanD的格式要求75 freq_items = {}76 l1 = scan_data(data, c1, min_support, freq_items) # 构建初始的频繁项集77 l = [l1]78# 最初的L1中的每个项集含有⼀个元素,新⽣成的项集应该含有2个元素,所以 k=279 k = 280while len(l[k - 2]) > 0:81 ck = apriori_gen(l[k - 2], k)82 lk = scan_data(data, ck, min_support, freq_items)83 l.append(lk)84 k += 1 # 新⽣成的项集中的元素个数应不断增加85return freq_itemsView Code1.2 FP-Growth算法实现:1)FP_Growth⽂件:在create_tree()函数中修改《机器学习实战》中的代码:############################################################################################## # 这⾥修改机器学习实战中的排序代码:ordered_items = [v[0] for v in sorted(local_data.items(), key=lambda kv: (-kv[1], kv[0]))]##############################################################################################1# -*- coding: utf-8 -*-2"""3@author: Infaraway4@time: 2017/4/15 16:075@Function:6"""7from DataMining.Unit6_FrequentPattern.FP_Growth.TreeNode import treeNode8910def create_tree(data_set, min_support=1):11"""12创建FP树13 :param data_set: 数据集14 :param min_support: 最⼩⽀持度15 :return:16"""17 freq_items = {} # 频繁项集18for trans in data_set: # 第⼀次遍历数据集19for item in trans:20 freq_items[item] = freq_items.get(item, 0) + data_set[trans]2122 header_table = {k: v for (k, v) in freq_items.iteritems() if v >= min_support} # 创建头指针表23# for key in header_table:24# print key, header_table[key]2526# ⽆频繁项集27if len(header_table) == 0:28return None, None29for k in header_table:30 header_table[k] = [header_table[k], None] # 添加头指针表指向树中的数据31# 创建树过程32 ret_tree = treeNode('Null Set', 1, None) # 根节点3334# 第⼆次遍历数据集35for trans, count in data_set.items():36 local_data = {}37for item in trans:38if header_table.get(item, 0):39 local_data[item] = header_table[item][0]40if len(local_data) > 0:41############################################################################################## 42# 这⾥修改机器学习实战中的排序代码:43 ordered_items = [v[0] for v in sorted(local_data.items(), key=lambda kv: (-kv[1], kv[0]))]44############################################################################################## 45 update_tree(ordered_items, ret_tree, header_table, count) # populate tree with ordered freq itemset46return ret_tree, header_table474849def update_tree(items, in_tree, header_table, count):50'''51 :param items: 元素项52 :param in_tree: 检查当前节点53 :param header_table:54 :param count:55 :return:56'''57if items[0] in in_tree.children: # check if ordered_items[0] in ret_tree.children58 in_tree.children[items[0]].increase(count) # incrament count59else: # add items[0] to in_tree.children60 in_tree.children[items[0]] = treeNode(items[0], count, in_tree)61if header_table[items[0]][1] is None: # update header table62 header_table[items[0]][1] = in_tree.children[items[0]]63else:64 update_header(header_table[items[0]][1], in_tree.children[items[0]])65if len(items) > 1: # call update_tree() with remaining ordered items66 update_tree(items[1::], in_tree.children[items[0]], header_table, count)676869def update_header(node_test, target_node):70'''71 :param node_test:72 :param target_node:73 :return:74'''75while node_test.node_link is not None: # Do not use recursion to traverse a linked list!76 node_test = node_test.node_link77 node_test.node_link = target_node787980def ascend_tree(leaf_node, pre_fix_path):81'''82遍历⽗节点,找到路径83 :param leaf_node:84 :param pre_fix_path:85 :return:86'''87if leaf_node.parent is not None:88 pre_fix_path.append(leaf_)89 ascend_tree(leaf_node.parent, pre_fix_path)909192def find_pre_fix_path(base_pat, tree_node):93'''94创建前缀路径95 :param base_pat: 频繁项96 :param treeNode: FP树中对应的第⼀个节点97 :return:98'''99# 条件模式基100 cond_pats = {}101while tree_node is not None:102 pre_fix_path = []103 ascend_tree(tree_node, pre_fix_path)104if len(pre_fix_path) > 1:105 cond_pats[frozenset(pre_fix_path[1:])] = tree_node.count106 tree_node = tree_node.node_link107return cond_pats108109110def mine_tree(in_tree, header_table, min_support, pre_fix, freq_items):111'''112挖掘频繁项集113 :param in_tree:114 :param header_table:115 :param min_support:116 :param pre_fix:117 :param freq_items:118 :return:119'''120# 从⼩到⼤排列table中的元素,为遍历寻找频繁集合使⽤121 bigL = [v[0] for v in sorted(header_table.items(), key=lambda p: p[1])] # (sort header table) 122for base_pat in bigL: # start from bottom of header table123 new_freq_set = pre_fix.copy()124 new_freq_set.add(base_pat)125# print 'finalFrequent Item: ',new_freq_set #append to set126if len(new_freq_set) > 0:127 freq_items[frozenset(new_freq_set)] = header_table[base_pat][0]128 cond_patt_bases = find_pre_fix_path(base_pat, header_table[base_pat][1])129 my_cond_tree, my_head = create_tree(cond_patt_bases, min_support)130# print 'head from conditional tree: ', my_head131if my_head is not None: # 3. mine cond. FP-tree132# print 'conditional tree for: ',new_freq_set133# my_cond_tree.disp(1)134 mine_tree(my_cond_tree, my_head, min_support, new_freq_set, freq_items)135136137def fp_growth(data_set, min_support=1):138 my_fp_tree, my_header_tab = create_tree(data_set, min_support)139# my_fp_tree.disp()140 freq_items = {}141 mine_tree(my_fp_tree, my_header_tab, min_support, set([]), freq_items)142return freq_itemsView Code2)treeNode对象⽂件1# -*- coding: utf-8 -*-2'''3@author: Infaraway4@time: 2017/3/31 0:145@Function:6'''789class treeNode:10def__init__(self, name_value, num_occur, parent_node):11 = name_value # 节点元素名称12 self.count = num_occur # 出现的次数13 self.node_link = None # 指向下⼀个相似节点的指针,默认为None14 self.parent = parent_node # 指向⽗节点的指针15 self.children = {} # 指向孩⼦节点的字典⼦节点的元素名称为键,指向⼦节点的指针为值1617def increase(self, num_occur):18"""19增加节点的出现次数20 :param num_occur: 增加数量21 :return:22"""23 self.count += num_occur2425def disp(self, ind=1):26print'' * ind, , '', self.count27for child in self.children.values():28 child.disp(ind + 1)View Code1.3 Eclat算法实现1# -*- coding: utf-8 -*-2"""3@author: Infaraway4@time: 2017/4/15 19:335@Function:6"""78import sys9import time10 type = sys.getfilesystemencoding()111213def eclat(prefix, items, min_support, freq_items):14while items:15# 初始遍历单个的元素是否是频繁16 key, item = items.pop()17 key_support = len(item)18if key_support >= min_support:19# print frozenset(sorted(prefix+[key]))20 freq_items[frozenset(sorted(prefix+[key]))] = key_support21 suffix = [] # 存储当前长度的项集22for other_key, other_item in items:23 new_item = item & other_item # 求和其他集合求交集24if len(new_item) >= min_support:25 suffix.append((other_key, new_item))26 eclat(prefix+[key], sorted(suffix, key=lambda item: len(item[1]), reverse=True), min_support, freq_items)27return freq_items282930def eclat_zc(data_set, min_support=1):31"""32 Eclat⽅法33 :param data_set:34 :param min_support:35 :return:36"""37# 将数据倒排38 data = {}39 trans_num = 040for trans in data_set:41 trans_num += 142for item in trans:43if item not in data:44 data[item] = set()45 data[item].add(trans_num)46 freq_items = {}47 freq_items = eclat([], sorted(data.items(), key=lambda item: len(item[1]), reverse=True), min_support, freq_items)48return freq_itemsView Code(三)试验阶段:这样我们就统⼀了三种算法的调⽤以及返回值,现在我们可以开始试验阶段了,我们在试验阶段分别根据最⼩⽀持度阈值和数据规模的变化来判断这三种算法的效率:⾸先我们先统⼀调⽤者三个算法:1def test_fp_growth(minSup, dataSetDict, dataSet):2 freqItems = fp_growth(dataSetDict, minSup)3 freqItems = sorted(freqItems.iteritems(), key=lambda item: item[1])4return freqItems567def test_apriori(minSup, dataSetDict, dataSet):8 freqItems = apriori_zc(dataSet, dataSetDict, minSup)9 freqItems = sorted(freqItems.iteritems(), key=lambda item: item[1])10return freqItems111213def test_eclat(minSup, dataSetDict, dataSet):14 freqItems = eclat_zc(dataSet, minSup)15 freqItems = sorted(freqItems.iteritems(), key=lambda item: item[1])16return freqItems然后实现数据规模变化的效率改变1def do_experiment_min_support():23 data_name = 'unixData8_pro.txt'4 x_name = "Min_Support"5 data_num = 15006 minSup = data_num / 678 dataSetDict, dataSet = loadDblpData(open("dataSet/" + data_name), ',', data_num)9 step = minSup / 5 # #################################################################10 all_time = []11 x_value = []12for k in range(5):1314 x_value.append(minSup) # ################################################################# 15if minSup < 0: # #################################################################16break17 time_fp = 018 time_et = 019 time_ap = 020 freqItems_fp = {}21 freqItems_eclat = {}22 freqItems_ap = {}23for i in range(10):24 ticks0 = time.time()25 freqItems_fp = test_fp_growth(minSup, dataSetDict, dataSet)26 time_fp += time.time() - ticks027 ticks0 = time.time()28 freqItems_eclat = test_eclat(minSup, dataSetDict, dataSet)29 time_et += time.time() - ticks030 ticks0 = time.time()31 freqItems_ap = test_apriori(minSup, dataSetDict, dataSet)32 time_ap += time.time() - ticks033print"minSup :", minSup, " data_num :", data_num, \34" freqItems_fp:", len(freqItems_fp), " freqItems_eclat:", len(freqItems_eclat), " freqItems_ap:", len(35 freqItems_ap)36print"fp_growth:", time_fp / 10, " eclat:", time_et / 10, " apriori:", time_ap / 1037# print_freqItems("show", freqItems_eclat)38 minSup -= step # #################################################################39 use_time = [time_fp / 10, time_et / 10, time_ap / 10]40 all_time.append(use_time)41# print use_time42 y_value = []43for i in range(len(all_time[0])):44 tmp = []45for j in range(len(all_time)):46 tmp.append(all_time[j][i])47 y_value.append(tmp)48 plot_pic(x_value, y_value, data_name, x_name)49return x_value, y_valueView Code然后实现最⼩⽀持度变化的效率改变1def do_experiment_data_size():23 data_name = 'kosarakt.txt'4 x_name = "Data_Size"5 data_num = 20000067 step = data_num / 5 # #################################################################8 all_time = []9 x_value = []10for k in range(5):11 minSup = data_num * 0.01012 dataSetDict, dataSet = loadDblpData(open("dataSet/"+data_name), '', data_num)13 x_value.append(data_num) # #################################################################14if data_num < 0: # #################################################################15break16 time_fp = 017 time_et = 018 time_ap = 019 freqItems_fp = {}20 freqItems_eclat = {}21 freqItems_ap = {}22for i in range(2):23 ticks0 = time.time()24 freqItems_fp = test_fp_growth(minSup, dataSetDict, dataSet)25 time_fp += time.time() - ticks026 ticks0 = time.time()27 freqItems_eclat = test_eclat(minSup, dataSetDict, dataSet)28 time_et += time.time() - ticks029 ticks0 = time.time()30# freqItems_ap = test_apriori(minSup, dataSetDict, dataSet)31# time_ap += time.time() - ticks032print"minSup :", minSup, " data_num :", data_num, \33" freqItems_fp:", len(freqItems_fp), " freqItems_eclat:", len(freqItems_eclat), " freqItems_ap:", len(freqItems_ap) 34print"fp_growth:", time_fp / 10, " eclat:", time_et / 10, " apriori:", time_ap / 1035# print_freqItems("show", freqItems_eclat)36 data_num -= step # #################################################################37 use_time = [time_fp / 10, time_et / 10, time_ap / 10]38 all_time.append(use_time)39# print use_time4041 y_value = []42for i in range(len(all_time[0])):43 tmp = []44for j in range(len(all_time)):45 tmp.append(all_time[j][i])46 y_value.append(tmp)47 plot_pic(x_value, y_value, data_name, x_name)48return x_value, y_valueView Code同时为了观察⽅便,我们需要对三种算法返回的结果进⾏绘图1# -*- coding: utf-8 -*-2"""3@author: Infaraway4@time: 2017/4/16 20:485@Function:6"""78import matplotlib.pyplot as plt91011def plot_pic(x_value, y_value, title, x_name):12 plot1 = plt.plot(x_value, y_value[0], 'r', label='Kulc') # use pylab to plot x and y13 plot2 = plt.plot(x_value, y_value[1], 'g', label='IR') # use pylab to plot x and y14# plot3 = plt.plot(x_value, y_value[2], 'b', label='Apriori') # use pylab to plot x and y15 plt.title(title) # give plot a title16 plt.xlabel(x_name) # make axis labels17 plt.ylabel('value ')18 plt.legend(loc='upper right') # make legend1920 plt.show() # show the plot on the screenView Code将两个部分统⼀执⾏:1if__name__ == '__main__':23# x_value, y_value = do_experiment_min_support()4# x_value, y_value = do_experiment_data_size()5# do_test()(四)实验结果分析:本次实验我们主要从以下⼏个⽅⾯来讨论三种算法的效率:数据规模⼤⼩最⼩⽀持度阈值长事物数据模式的稠密性4.1 数据规模⼤⼩:数据集:unxiData8规模:900-1500Min_support = 1/30时 Min_support = 1/20时数据集:kosarakt规模:6000-10000Min_support = 1/50 Min_support = 1/80 Min_support = 1/100结论:⼀般情况下,数据规模越⼤,使⽤Apriori算法的效率越低,因为该算法需要多次扫描数据库,当数据量越⼤时,扫描数据库带来的消耗越多。
Apriori算法实验报告及程序

Apriori算法实验陈说之迟辟智美创作学号:姓名:专业:计算机应用技术教师:计算机学院目录1 Apriori实验1.1 实验布景现在, 数据挖掘作为从数据中获取信息的有效方法, 越来越受到人们的重视.关联规则挖掘首先是用来发现购物篮数据事务中各项之间的有趣联系.从那以后, 关联规则就成为数据挖掘的重要研究方向,它是要找出隐藏在数据间的相互关系.目前关联规则挖掘的研究工作主要包括:Apriori算法的扩展、数量关联规则挖掘、关联规则增量式更新、无须生成候选项目集的关联规则挖掘、最年夜频繁项目集挖掘、约束性关联规则挖掘以及并行及分布关联规则挖掘算法等.关联规则的挖掘问题就是在事务数据库D 中找出具有用户给定的满足一定条件的最小支持度Minsup和最小置信度Minconf的关联规则.1.1.1 国内外研究概况1993年,Agrawal等人首先提出关联规则概念,关联规则挖掘便迅速受到数据挖掘领域专家的广泛关注.迄今关联规则挖掘技术获得了较为深入的发展.Apriori算法是关联规则挖掘经典算法.针对该算法的缺点,许多学者提出了改进算法,主要有基于哈希优化和基于事务压缩等.1.1.2 发展趋势关联规则挖掘作为数据挖掘的重要研究内容之一, 主要研究事务数据库、关系数据库和其他信息存储中的年夜量数据项之间隐藏的、有趣的规律.关联规则挖掘最初仅限于事务数据库的布尔型关联规则, 近年来广泛应用于关系数据库, 因此, 积极开展在关系数据库中挖掘关联规则的相关研究具有重要的意义.近年来,已经有很多基于Apriori算法的改进和优化.研究者还对数据挖掘的理论进行了有益的探索,将概念格和粗拙集应用于关联规则挖掘中,获得了显著的效果.到目前为止,关联规则的挖掘已经取得了令人瞩目的成果,包括:单机环境下的关联规则挖掘算法;多值属性关联规则挖掘;关联规则更新算法;基于约束条件的关联规则挖掘;关联规则并行及分布挖掘算法等.1.2 实验内容与要求1.2.1 实验内容编程实现Apriori算法:要求使用‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’,‘h’,‘i’,‘j’10个项目随机发生数据记录并存入数据库.从数据库读取记录进行Apriori实验,获得频繁集以及关联规则,实现可视化.并用课堂上PPT的实例测试其正确性.1.2.2 实验要求1、法式结构:包括前台工具和数据库;2、设定项目种类为10个,随机发生事务,生成数据库;3、正确性验证(可用课堂上的例子);4、算法效率的研究:在支持度固定命据量分歧的时候丈量运行时间;在数据量固定,支持度分歧的时候丈量运行时间;5、注意界面的设计,输入最小支持度和最小可信度,能够输出并显示频繁项目集以及关联规则.1.2.3 实验目的1、加强对Apriori算法的理解;2、熬炼分析问题、解决问题并入手实践的能力.2 Apriori算法分析与实验环境2.1 Apriori算法的描述Apriori算法是一种找频繁项目集的基本算法.其基来源根基理是逐层搜索的迭代:频繁K项Lk 集用于搜索频繁(K+1)项集Lk+1,如此下去,直到不能找到维度更高的频繁项集为止.这种方法依赖连接和剪枝这两步来实现.算法的第一次遍历仅仅计算每个项目的具体值的数量,以确定年夜型l项集.随后的遍历,第k次遍历,包括两个阶段.首先,使用在第(k-1)次遍历中找到的年夜项集Lk-1和发生候选项集Ck.接着扫描数据库,计算Ck中候选的支持度.用Hash树可以有效地确定Ck中包括在一个给定的事务t中的候选.如果某项集满足最小支持度, 则称它为频繁项集.2.2 Apriori算法的步伐步伐如下:1、设定最小支持度s和最小置信度c;2、Apriori算法使用候选项集.首先发生出候选的项的集合,即候选项集,若候选项集的支持度年夜于或即是最小支持度,则该候选项集为频繁项集;3、在Apriori算法的过程中,首先从数据库读入所有的事务,每个项都被看作候选1-项集,得出各项的支持度,再使用频繁1-项集集合来发生候选2-项集集合,因为先验原理保证所有非频繁的1-项集的超集都是非频繁的;4、再扫描数据库,得出候选2-项集集合,再找出频繁2-项集,并利用这些频繁2-项集集合来发生候选3-项集;5、重复扫描数据库,与最小支持度比力,发生更高条理的频繁项集,再从该集合里发生下一级候选项集,直到不再发生新的候选项集为止.2.3 开发环境2.3.1 软件环境(1)编程软件:Jdk开发包+eclipse集成开发环境Eclipse 是一个开放源代码的、基于Java的可扩展开发平台.就其自己而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境.幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK).(2)数据库软件:SQL Server 2008SQL Server 2008 在Microsoft的数据平台上发布,可以组织管理任何数据.可以将结构化、半结构化和非结构化文档的数据直接存储到数据库中.可以对数据进行查询、搜索、同步、陈说和分析之类的把持.数据可以存储在各种设备上,从数据中心最年夜的服务器一直到桌面计算机和移动设备,它都可以控制数据而不用管数据存储在哪里.(3)办公软件:Excel 2010Excel是一款办公软件.它是微软办公套装软件office的重要的组成部份,它是集统计分析、数据处置和辅助决策等功能于一身,现在金融、统计财经、管理等众多领域广泛应用.本实验主要用来为固定命据量改变最小支持数以及固定最小支持数改变数据量两种情况进行时间分析提供可视化图表.2.3.2 硬件环境装有Windows 7 旗舰版电脑.2.4 本章小结本章的内容主要是为了引出本实验的主要算法以及对算法的实现环境做了介绍.3 算法的设计3.1 Apriori图3.1 Apriori实验流程图3.2 主要的数据结构与函数3.2.1 数据结构class Transaction{public int pid;public String itemset;}该类暗示表中的一条记录.class Dao{public ArrayList<Transaction> Query(String sql)}该类用于访问数据库把持.class Kfp{public char kfpstr[]=new char[Apriori.ITEMSIZE];public int index=-1;public int support=0;public boolean isfp=true;}该类代表一个频繁项目.3.2.2 主要的法式Java 中最经常使用的集合类是List 和Map. List 的具体实现包括ArrayList 和Vector,它们是可变年夜小的列表,比力适合构建、存储和把持任何类型对象的元素列表. List 适用于按数值索引访问元素的情形.HashMap:Map接口的经常使用实现类,系统<key,value>当做一个整体进行处置,系统总是根据Hash算法来计算<key,value>的存储位置,这样可以保证能快速存、取 Map的<key,value>对.ArrayList<Transaction> alTransactions:保管表中的所有记录ArrayList<Kfp> alKfpsl:临时存储频繁项目的集合,存储连接后的结果ArrayList<Kfp> SureFpset:保管频繁k项集ArrayList<Kfp> SureFpsetPrio:保管频繁k-1项集ArrayList<String> notFpList:保管一定不是频繁项目的集合,用于剪枝HashMap<String, Integer> KfpSuppor:频繁项目集及其对应的支持数HashMap<String,Double> guanlianguize:关联规则及其置信度3.2.3 连接与剪枝把持对连接把持的两个字符串(长度为k),它们必需有k-1个相同的字符才华做连接把持.例如:abc和abd可以连接成abcd,abd和bcd可以连接成abcd,而abc和ade就不成以做连接把持.整个连接过程类似归并排序中的归并把持对任一频繁项目集的所有非空子集也必需是频繁的,反之,如果某个候选的非空子集不是频繁的,那么该候选集肯定不是频繁的,将其剪枝.3.3 本章小结本章主要介绍了算法设计的整体流程而且也对主要法式和把持作了简要的说明.4 数据库的设计与数据的来源本实验的数据均存储于数据库中.数据库yuzm中共发生6张表.表test为测试用表,用于法式的正确性验证.还有5张表存储随机发生的实验数据.其中数据库的结构如下图所示.图4.1 数据库结构表test为PPT上的实例,用于正确性验证.数据的item个数为5,其中的九行数据均由SQL语句发生,表的每一行都是一个“0”“1”的字符串,字符串长度即是商品种类,其中“0”暗示该商品不存在,“1”暗示该商品存在.表的全部数据如图4.2.图4.2 表test4.2 实验数据5张表是通过算法随机发生的具有分歧数据量的数据集,假设商品种类为10种,表的每一行都是一个“0”“1”的字符串,字符串长度即是商品种类,其中“0”暗示该商品不存在,“1”暗示该商品存在.其中表data1共随机发生1万行数据,表data2发生5万行数据,表data3发生25万行数据,表data4发生50万行数据,表data5发生75万行数据.部份数据如图4.3.图4.3 实验用表(部份)4.3 本章小结本章主要对数据库的设计与数据来源做出了说明.5 实验结果与性能分析5.1 Apriori实验界面其中可信度可自由设置,默认为0.7.而支持度记为最小支持度与数据量的比例.实验数据可以下拉选择6张表中的任意一张.如下图所示:5.2 实验的正确性验证运行法式,我们选择表test,即可进行正确性验证,实验结果如下图:最终实验结果与ppt的结果相吻合,标明法式编写正确.5.3 实验性能分析为了对本法式的实验进行性能分析,我们分别采纳固定命据量改变最小支持数以及固定最小支持数改变数据量两种情况进行时间分析,其中最小置信度设为0.7不变.设支持度为0.2,最小可信度为0.7.具体实验数据量与执行时间如下:数据量(万行) 1 5 25 50 75时间(秒)图5.3 数据量对性能的影响设实验数据量固定改变最小支持度,具体如下所示:表5.2 最小支持度对性能的影响最小支持度49时间(秒/ 1万)时间(秒/ 5万)时间(秒/ 25万)图5.4 最小支持度对性能的影响由以上实验我们可以看出,实验时间会随着数据量的增年夜而增年夜,而且随着最小支持度的增年夜而减小.而且他们之间的变动类似于某种指数函数的变动趋势.Apriori的时间主要消耗在4个方面:1、利用K频繁集连接发生K+1候选集时,判断连接的条件时比力的次数太多.假设项集个数为m的频繁集合Lk,判断连接条件时比力的时间复杂度为O(K*m2).而且本实验的m都很年夜;2、对Ck中任意的一个c的k个(k-1)子集是否都在Lk-1中.在平均情况下,对所有候选k项集需要扫描次数为|Ck|*|Lk-1|*k/2;3、为了获得所有的候选频集的支持度,需要扫描N次;4、扫描一次数据库需时间O(k|T|).|T|为交易数量,k交易长度5.4 本章小结Apriori算法因自身需要屡次扫描数据库,而且经过复杂的连接剪枝把持而发生年夜量候选集以及进行年夜量的模式匹配计算的缺陷,使得其在I/O上的花费时间很多,从而招致算法的效率不是太高.6 总结与体会通过本次实验,让我明白了什么是Apriori算法和数据之间的关联性,Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法,为以后进步学习数据挖掘知识打下了良好的基础.同时我也更加深刻理解了Apriori算法的原理及其实现的内部细节,同时通过实现这一经典的数据挖掘算法,也让我更深刻的体会到数据挖掘对知识发现的重要性,尽管实现了算法,但其中可能还有可以改进的处所,尤其是法式的运行效率方面.Apriori算法实验不单使得我对该算法的理解更加上升了一个条理,同时也使得我更加了解了java编程语言,使用更加驾轻就熟.import java.awt.BorderLayout;import java.awt.Font;import java.awt.GridLayout;import java.awt.Panel;import java.awt.TextArea;import java.awt.TextField;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.Set;import javax.swing.JButton;import javax.swing.JComboBox;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JTextField;import org.omg.CORBA.PUBLIC_MEMBER;public class Apriori extends JFrame implements ActionListener{//////////////////////////////////////////////////////public static int ITEMSIZE=10;public final int FRAMEWIDTH=800;public final int FRAMEHEIGHT=600;///////////////////////////////////////////////////////JPanel up=null;JPanel up_up=null;TextField textFieldName[]=null;JPanel up_down=null;JPanel up_down_left=null;JLabel conflabel=null;JLabel c1=null;JLabel c2=null;JLabel c3=null;JLabel c4=null;JLabel c5=null;JLabel c6=null;JLabel c7=null;JLabel c8=null;JTextField conf=null;JLabel supportlabel=null;JTextField support=null;JPanel up_down_right=null;JComboBox jComboBoxDateSize=null;//下拉框JButton jButtonMine=null;JPanel down=null;TextArea textArea=null;int fpstep=1;int fpindex=0;Dao dao=null;double MinSupport=0.20;double MinConfi=0.70;double DateSize=9.0;ArrayList<Transaction> alTransactions=null;ArrayList<Kfp> alKfps=null;ArrayList<String> notFpList=null;ArrayList<Kfp> SureFpset=null;ArrayList<Kfp> SureFpsetPrio=null;HashMap<String, Integer> KfpSupport=null;ArrayList<String> alsurekfpstr=null;HashMap<String,Double> guanlianguize=null;ArrayList<String> isaddarrStrings=null;int [][]AuxArr=null;public static void main(String[] args){Apriori A=new Apriori();}public Apriori(){JPanel up=new JPanel(new GridLayout(2, 1));JPanel up_up=new JPanel(new GridLayout(1, ITEMSIZE)); //TextField textFieldName[]=new TextField[ITEMSIZE]; //for(int i=0;i<ITEMSIZE;i++)//{//textFieldName[i]=new TextField();//up_up.add(textFieldName[i]);//}c1=new JLabel(" 数");up_up.add(c1);c2=new JLabel(" 据");up_up.add(c2);c3=new JLabel(" 挖");up_up.add(c3);c4=new JLabel(" 掘");up_up.add(c4);c5=new JLabel(" 实");up_up.add(c5);c6=new JLabel(" 验");up_up.add(c6);c7=new JLabel(" --------");up_up.add(c7);c8=new JLabel(" Apriori");up_up.add(c8);up_down=new JPanel(new GridLayout(1, 2));up_down_left=new JPanel(new GridLayout(1, 4));conflabel=new JLabel("可信度:");conf=new JTextField();conf.setText("0.7");supportlabel=new JLabel("支持度:");support=new JTextField();support.setText("0.2");up_down_left.add(conflabel);up_down_left.add(conf);up_down_left.add(supportlabel);up_down_left.add(support);up_down_right=new JPanel(new GridLayout(1, 2)); jComboBoxDateSize=new JComboBox();//下拉框jComboBoxDateSize.addItem("test"); jComboBoxDateSize.addItem("data1"); jComboBoxDateSize.addItem("data2"); jComboBoxDateSize.addItem("data3"); jComboBoxDateSize.addItem("data4"); jComboBoxDateSize.addItem("data5"); jComboBoxDateSize.addActionListener(this);jButtonMine=new JButton("开始挖掘");jButtonMine.addActionListener(this);up_down_right.add(jComboBoxDateSize);up_down_right.add(jButtonMine);up_down.add(up_down_left);up_down.add(up_down_right);up.add(up_up);up.add(up_down);down=new JPanel(new BorderLayout()) ;textArea=new TextArea();//textArea.setFont(new Font(Font.DIALOG,Font.ITALIC , 20)); textArea.setFont(new Font(Font.DIALOG,Font.PLAIN , 20));down.add(textArea);this.setLayout(new BorderLayout());this.setSize(FRAMEWIDTH, FRAMEHEIGHT);this.setLocation(100, 100);this.setSize(this.FRAMEWIDTH, this.FRAMEHEIGHT);this.setDefaultClo搜索引擎优化peration(JFrame.EXIT_ON_CLOSE); this.setTitle("Apriori");//up.setSize(this.FRAMEWIDTH, 100);this.add(up,BorderLayout.NORTH);//down.setLocation(0, 100);//down.setSize(this.FRAMEWIDTH, this.FRAMEHEIGHT-100);this.add(down);this.setVisible(true);}public void InitDate(String table){fpstep=1;AuxArr=new int[ITEMSIZE+1][ITEMSIZE+1];alKfps=new ArrayList<Kfp>();notFpList=new ArrayList<String>();SureFpset=new ArrayList<Kfp>();SureFpsetPrio=new ArrayList<Kfp>();dao=new Dao();KfpSupport=new HashMap<String, Integer>();alsurekfpstr=new ArrayList<String>();guanlianguize=new HashMap<String,Double>();isaddarrStrings=new ArrayList<String>();alTransactions=dao.Query("select * from "+table);this.DateSize=alTransactions.size();}public void ShowkFp(ArrayList<Kfp> SureFpset){int steptemp=fpstep;textArea.append("频繁"+(steptemp)+"项集\r\n");//System.out.println();for(int i=0;i<SureFpset.size();i++){Kfp k=SureFpset.get(i);int tempindex=k.index;String string=String.copyValueOf(k.kfpstr, 0, ++tempindex);int support=KfpSupport.get(string);textArea.append(string+"-----"+support+"-----"+support/DateSize+"\r\n"); //System.out.println(string+"\r\n");}}public void ShowkFp2(HashMap<String,Double> SureFpset){textArea.append("关联规则\r\n");Set<String> keys=(Set<String>) SureFpset.keySet();for(String keyString:keys){textArea.append(keyString+"-----------"+SureFpset.get(keyString)+"\r\n");; }}public void DataMine(){int fpsteptemp=0;if(fpstep == 1){for(int i=0;i<Apriori.ITEMSIZE;i++){Kfp kfp=new Kfp();kfp.kfpstr[++kfp.index]=(char) ('a'+i);kfp.support=0;kfp.isfp=false;alKfps.add(kfp);}DealSupport();SaveNotFpBySupport();SaveSureFp();ShowkFp(alKfps);fpstep++;}while(!alKfps.isEmpty()){alKfps.clear();for (int i = 0; i < SureFpset.size(); i++){Kfp k1 = SureFpset.get(i);for (int j = i + 1; j < SureFpset.size(); j++){Kfp k2 = SureFpset.get(j);Kfp resultKfp = Joint(k1, k2);int tempindex=resultKfp.index;String string=String.copyValueOf(resultKfp.kfpstr, 0, ++tempindex);if(string.charAt(0) == 0)continue;SubSet subSet= new SubSet();ArrayList<String> alStrings=subSet.displaySubSet1(string.toCharArray()); int p=0;for(;p<alStrings.size();p++){String string2=alStrings.get(p);if(notFpList.contains(string2))break;}if(p != alStrings.size())continue;if (!isaddarrStrings.contains(string)) {isaddarrStrings.add(string);alKfps.add(resultKfp);}}}SureFpsetPrio.clear();for(int i=0;i<SureFpset.size();i++)SureFpsetPrio.add(SureFpset.get(i));Guanlianguize();SureFpset.clear();DealSupport();SaveNotFpBySupport();// Cut();if (!alKfps.isEmpty()){SaveSureFp();ShowkFp(SureFpset);}fpstep++;}}public void Guanlianguize(){for(int i=0;i<SureFpsetPrio.size();i++){Kfp k=SureFpsetPrio.get(i);int len = k.index;String string=String.copyValueOf(k.kfpstr, 0, len+1);if(!alsurekfpstr.contains(string))alsurekfpstr.add(string);}SubSet s=new SubSet();for(int i=0;i<alsurekfpstr.size();i++){String kfpstr=alsurekfpstr.get(i);char []kfpchararr=kfpstr.toCharArray();ArrayList<String> aList=s.SubSet3(kfpchararr,kfpstr.length());for(int j=0;j<aList.size();j++){String guizetemp="";String kfpstr1=aList.get(j);char []kfpchararr1=kfpstr1.toCharArray();int indexinkfp=0;int indexinchararr1=0;while(indexinkfp < kfpchararr.length && indexinchararr1 < kfpchararr1.length) {if(kfpchararr1[indexinchararr1] != kfpchararr[indexinkfp]){guizetemp=guizetemp+kfpchararr[indexinkfp];indexinkfp++;}{indexinchararr1++;indexinkfp++;}}while(indexinkfp < kfpchararr.length)guizetemp=guizetemp+kfpchararr[indexinkfp++];double support1=(double)KfpSupport.get(kfpstr);double support2=(double)KfpSupport.get(kfpstr1);if(support1/support2 > MinConfi){String temp=kfpstr1+"-------->"+guizetemp;guanlianguize.put(temp,support1/support2);}}}ShowkFp2(guanlianguize);alsurekfpstr.clear();guanlianguize.clear();}public Kfp Joint(Kfp k1,Kfp k2){Kfp resultKfp=new Kfp();int temp_len=k1.index+1;char temp1[]=new char[temp_len];char temp2[]=new char[temp_len];for(int i=0;i<=k1.index;i++){temp1[i]=k1.kfpstr[i];temp2[i]=k2.kfpstr[i];}SubSet s=new SubSet();ArrayList<String> alStrings1=s.SubSet2(temp1,fpstep);ArrayList<String> alStrings2=s.SubSet2(temp2,fpstep);char result[]=new char[temp_len+1];boolean flag=false;for(int i=0;i<alStrings1.size();i++){String tempstr=alStrings1.get(i);if(alStrings2.contains(tempstr)){int p=0;int q=0;int j=0;while(p != temp1.length && q != temp2.length){if( p != temp1.length && q != temp2.length && temp1[p] > temp2[q]) {result[j++]=temp2[q];}if(p != temp1.length && q != temp2.length && temp1[p] == temp2[q]){result[j++]=temp2[q];q++;p++;}if(p != temp1.length && q != temp2.length && temp1[p] < temp2[q]){result[j++]=temp1[p];p++;}}if(p < temp1.length){while(p!=temp1.length)result[j++]=temp1[p++];}if(q < temp2.length){//System.out.println("fpstep="+fpstep+","+"j="+j+","+"q="+q+","+"temp_len="+temp_l en);while(q!=temp2.length)result[j++]=temp2[q++];}flag=true;}if(flag == true)break;}for(int i=0;i<temp_len+1;i++){resultKfp.kfpstr[++resultKfp.index]=result[i];}return resultKfp;}public void DealSupport(){int len=alTransactions.size();for(int i=0;i<len;i++){Transaction t=alTransactions.get(i);String itemset=t.itemset;int num=0;char []tempchar=new char[ITEMSIZE];for(int i1=0;i1<itemset.length();i1++){。
apriori算法python代码

apriori算法python代码Apriori算法是一种经典的关联规则挖掘算法,用于在大规模数据集中挖掘频繁项集和关联规则。
下面是Apriori算法的Python实现代码:```python# Apriori算法实现def apriori(dataSet, minSupport=0.5):# 获取所有不重复的项值def createC1(dataSet):C1 = []for transaction in dataSet:for item in transaction:if not [item] in C1:C1.append([item])C1.sort()return list(map(frozenset, C1))# 过滤掉不满足最小支持度的项集def scanD(D, Ck, minSupport):ssCnt = {}for tid in D:for can in Ck:if can.issubset(tid):if not can in ssCnt:ssCnt[can] = 1else:ssCnt[can] += 1numItems = float(len(D))retList = []supportData = {}for key in ssCnt:support = ssCnt[key] / numItems if support >= minSupport:retList.insert(0, key)supportData[key] = supportreturn retList, supportData# 生成候选项集def aprioriGen(Lk, k):retList = []lenLk = len(Lk)for i in range(lenLk):for j in range(i + 1, lenLk): L1 = list(Lk[i])[:k - 2]L2 = list(Lk[j])[:k - 2]L1.sort()L2.sort()if L1 == L2:retList.append(Lk[i] | Lk[j])return retList# Apriori算法主函数D = list(map(set, dataSet))C1 = createC1(dataSet)L1, supportData = scanD(D, C1, minSupport)L = [L1]k = 2while (len(L[k - 2]) > 0):Ck = aprioriGen(L[k - 2], k)Lk, supK = scanD(D, Ck, minSupport)supportData.update(supK)L.append(Lk)k += 1return L, supportData```上述代码中,`createC1()`函数用于生成单个项的候选项集,`scanD()`函数用于过滤不满足最小支持度的项集,`aprioriGen()`函数用于生成候选项集,`apriori()`函数是Apriori算法的主函数,用于挖掘频繁项集和关联规则。
叶志伟数据挖掘实验指导书(算法编程部分)

《数据挖掘与数据仓库》实验指导书2013年计算机学院计算应用实验1 Apriori算法实现一、实验目的1、掌握Apriori算法对于关联规则挖掘中频繁集的产生以及关联规则集合的产生过程;2、根据算法描述编程实现算法,调试运行。
并结合相关实验数据进行应用,得到分析结果。
数据和删除数据的操作。
实验类型:综合计划课间:2学时二、实验内容1、频繁项集的生成与Apriori算法实现;2、关联规则的生成过程与Rule-generate算法实现;3、结合样例对算法进行分析;三、实验步骤编写程序完成下列算法:1、Apriori算法输入:数据集D;最小支持数minsup_count;输出:频繁项目集LL1={large 1-itemsets}For (k=2; Lk-1≠Φ; k++)Ck=apriori-gen (Lk-1); // Ck是k个元素的候选集For all transactions t∈D dobegin Ct=subset(Ck,t); //Ct是所有t包含的候选集元素for all candidates c ∈Ct do c.count++;endLk={c ∈Ck| c.count ≧ minsup_count }EndL=∪Lk;2、apriori-gen (Lk-1) 候选集产生算法输入: (k-1)-频繁项目集Lk-1输出: k-频繁项目集CkFor all itemset p∈Lk-1 doFor all itemset q∈Lk-1 doIf p.item1=q.item1, p.item2=q.item2, …,p.itemk-2=q.itemk-2, p.itemk-1<q.itemk-1 thenbegin c=p∞qif has_infrequent_subset(c, Lk-1)then delete celse add c to CkEndReturn Ck3、has_infrequent_subset(c, Lk-1)功能:判断候选集的元素输入:一个k-频繁项目集Lk-1 ,(k-1)-频繁项目集Lk-1输出:c是否从候选集中删除的布尔判断For all (k-1)-subsets of c doIf Not(S∈Lk-1) THEN return TRUE;Return FALSE;4、Rule-generate(L,minconf)输入:频繁项目集;最小信任度输出:强关联规则算法:FOR each frequent itemset lk in Lgenerules(lk,lk);5、Genrules递归算法:Genrules(lk:frequent k-itemset, xm:frequent m-itemset)X={(m-1)-itemsets xm-1 | xm-1 in xm};For each xm-1 in XBEGIN conf=support(lk)/support(xm-1);IF (conf≧minconf) THENBEGIN输出规则:xm-1->(lk-xm-1),support,confidence;IF (m-1)>1) THEN genrules(lk,xm-1);END;END;结合相关样例数据对算法进行调试,并根据相关实验结果对数据进行分析,四、实验报告要求1、用C语言或者其他语言实现上述相关算法。
关联规则算法Apriori的学习与实现

关联规则算法Apriori的学习与实现(2011-07-18 11:28:52)首先我们来看,什么是规则?规则形如”如果…那么…(If…Then…)”,前者为条件,后者为结果。
关联规则挖掘用于寻找给定数据集中项之间的有趣的关联或相关关系。
关联规则揭示了数据项间的未知的依赖关系,根据所挖掘的关联关系,可以从一个数据对象的信息来推断另一个数据对象的信息。
例如购物篮分析。
牛奶⇒面包[支持度:3%,置信度:40%]支持度3%意味3%顾客同时购买牛奶和面包。
置信度40%意味购买牛奶的顾客40%也购买面包。
规则的支持度和置信度是两个规则兴趣度度量,它们分别反映发现规则的有用性和确定性。
关联规则是有趣的,如果它满足最小支持度阈值和最小置信度阈值。
这些阈值可以由用户或领域专家设定。
我们先来认识几个相关的定义:定义1:支持度(support)支持度s是事务数据库D中包含A U B的事务百分比,它是概率P(A U B),即support (A B)=P(A U B),它描述了A和B这两个物品集的并集在所有的事务中出现的概率。
定义2:置信度(confidence)可信度为事务数据库D中包含A的事务中同时也包含B的百分比,它是概率P(B|A),即confidence(A B)=P(B|A)。
定义3:频繁项目集支持度不小于用户给定的最小支持度阈值(minsup)的项集称为频繁项目集(简称频集),或者大项目集。
所有的频繁1-项集记为L1。
假设有如下表的购买记录。
顾客项目1orange juice, coke2milk, orange juice, window cleaner3orange juice, detergent4orange juice, detergent, coke5window cleaner将上表整理一下,得到如下的一个2维表Orange Win Cl Milk Coke DetergentOrange41122WinCl12100Milk11100Coke20021Detergent10002上表中横栏和纵栏的数字表示同时购买这两种商品的交易条数。
(数据挖掘)关联规则挖掘——Apriori算法、fp—Tree算法

C2
{A,支E持} 度<50 25% {B,C} 50%
{B,E} 75%
{C,E} 50%
{A,C} 50%
L2
{B,C} {B,E}
50% 75%
{C,E} 50%
从K2中求可用来计算的的三项集 {A,C}+{B,C} {A,B,C} {A,C}+{B,E} 超过三项 {A,C}+{C,E} {A,C,E} {B,C}+{B,E} {B,C,E} {B,C}+{C,E} {B,C,E} {B,E}+{C,E} {B,C,E}
Null
I2
I2:6
I1:2
I1
I1:3
I3:2
I4:1
I3:2
I3
I4
I4:1
I5
I5:1
I3:1
I5:1
加入第九个事务(I2,I1,I3)
Item-name Node-head
Null
I2
I2:7
I1:2
I1
I1:4
I3:2
I4:1
I3:2
I3
I4
I4:1
I5
I5:1
I3:2
I5:1
第二步、FP-growth
Null
I2
I2:4
I1
I1:2
I4:1
I3:1
I3
I4
I4:1
I5
I5:1
加入第五个事务(I1,I3)
Item-name Node-head
Null
I2
I2:4
I1:1
I1
I1:2
I4:1
I3:1
I3:1
I3
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、原Apriori算法
1、算法原理:
该算法的基本思想是:首先找出所有的频集,这些项集出现的频繁性至少和预定义的最小支持度一样。
然后由频集产生强关联规则,这些规则必须满足最小支持度和最小可信度。
然后使用第1步找到的频集产生期望的规则,产生只包含集合的项的所有规则,其中每一条规则的右部只有一项,这里采用的是中规则的定义。
一旦这些规则被生成,那么只有那些大于用户给定的最小可信度的规则才被留下来。
为了生成所有频集,使用了递推的方法
(1)L1 = find_frequent_1-itemsets(D); // 挖掘频繁1-项集,比较容易
(2)for (k=2;Lk-1 ≠Φ ;k++) {
(3)Ck = apriori_gen(Lk-1 ,min_sup); // 调用apriori_gen方法生成候选频繁k-项集
(4)for each transaction t ∈ D { // 扫描事务数据库D
(5)Ct = subset(Ck,t);
(6)for each candidate c ∈ Ct
(7)c.count++; // 统计候选频繁k-项集的计数
(8)}
(9)Lk ={c ∈ Ck|c.count≥min_sup} // 满足最小支持度的k-项集即为频繁k-项集
(10) }
(11)return L= ∪ k Lk; // 合并频繁k-项集(k>0)
2、算法流程
①首先单趟扫描数据集,计算各个一项集的支持度,根据给定的最小支持度闵值,得到一项频繁集L1。
②然后通过连接运算,得到二项候选集,对每个候选集再次扫描数据集,得出每个候选集的支持度,再与最小支持度比较。
得到二项频繁集L2。
③如此进行下去,直到不能连接产生新的候选集为止。
④对于找到的所有频繁集,用规则提取算法进行关联规则的提取。
3、算法的不足:
(1)数据库重复扫描的次数太多。
在由CK寻找LK的过程中,CK中的每一项都需要扫描事务数据库进行验证,以决定其是否加入Lk,存在的频繁K-项集越大,重复扫描的次数就越多。
这一过程耗时太大,增加了系统1/0开销,处理效率低[10],不利于实际应用。
(2)产生的候选集可能过于庞大。
如果一个频繁1-项集包含100个项,那么频繁2-项集就有C2
100个,为找到元素个数为100的频繁项集,如{b1,b2,…,b100},那么就要扫描数据库100次,产生的候选项集总个数为:
举例:
对于一个这样庞大的项集,计算机难以存储和计算,挖掘效率低下。
二、算法的改进1
1、改进方法:
性质1:频繁项集的所有非空子集都必须是频繁的。
(Apriori性质,记为性质1)
性质2:若频繁K-项集Lk中各个项可以做链接产生Lk+1
,则Lk中每个元素在Lk中出现的次数应大于或等于K,若小于K,则删除该项在Lk中所有的事务集[11]。
(Apriori性质的推论,记为性质2)
改进的方法:在连接之后得到的候选频繁k项,直接进行最小支持度判断,并进行剪枝,从而直接得到频繁k项集,避免候选项集可能过大的问题;
2、算法的流程
①首先单趟扫描数据集,计算各个一项集的支持度,根据给定的最小支持度阈值,得到一项频繁集L1。
②然后通过连接运算,对于每个连接的到项直接进行最小支持度判断,如果大于最小支持度的加入频繁二项集,如果小于则舍弃,循环直到连接完毕;得到二项频繁集L2。
③如此进行下去,直到不能连接产生新的频繁项集为止。
3、代码实现的描述(详细描述文末附上):
使用C++,构造了一个Apriori类:
class Apriori
{
public:
//初始化,输入数据源,得到原始数据集、频繁1项集
void init(string fileName); //连接频繁k项集、并且直接剪枝,得到频繁k+1项集,加入到容器item_list void apri_gen();;//连接频繁k项集、并且直接剪枝,得到频繁k+1项集,加入到频繁项集集合frequentvec中float calculateSup(vector<string> judge_item); //求候选项的支持度
vector<string> mergeItem(vector<string> vect1,vector<string> vect2,int round); //判断两个项是否可以合并成一个新的项集做为新的候选项,能则合并,不能的返回空容器
void showItem();//输出频繁项集
private:
vector<set<string>> datavec; //原始数据集
int trancount; //原始数据项数量
vector<vector<pair<vector<string>,float>>> frequentvec; //频繁项集的集合
double minsup; //设置最小支持度和最小置信度
double minconf; //设置最小支持度和最小置信度
};
运行结果:
效果对比:
数据集大小:9835
数据元素多少:170
置信度:0.05
原始:频繁1项集28
候选2项集2^28
频繁2项集3
改进后:频繁1项集28
频繁2项集3
算法的改进2
第一次扫描数据库时,对于数据库中的数据,利用各项元素的数字编号来替换各数据元素的名称;即将数据元素的名称字符传用数字来替换,从而减少在求各候选项的支持度时的资源消耗;
代码中的改进之处,
string类型的元素转为对应的int代号:储存频繁项集的容器由vector<vector<pair<vector<string>,float>>>变为vector<vector<pair<vector<int>,float>>>;然后对代码进行相应的调整,使得代码正常运行;
代码的描述:
class Apriori
public:
void init(string fileName); //初始化,输入数据源,得到原始数据集、频繁1项集
void apri_gen();//连接频繁k项集、并且直接剪枝,得到频繁k+1项集,加入到频繁项集集合frequentvec中float calculateSup(vector<int> judge_item); //求候选项的支持度
vector<int> mergeItem(vector<int> vect1,vector<int> vect2,int round); //判断两个项是否可以合并成一个新的项集做为新的候选项,能则合并,不能的返回空容器
void showItem();//输出频繁项集
private:
vector<set<int>> dataNumVec;//原始数据集转换出来的、数据项用代号来表示的数据
map<string,int> reflection; //原始数据中各个不同的元素的代号映射,数据元素从1开始编号
int trancount; //原始数据项数量
vector<vector<pair<vector<int>,float>>> frequentvec; //频繁项集集合,储存各项以及其支持度double minsup; //设置最小支持度和最小置信度
};
运行结果:
效果对比:
改进后14.496;14.549;14.577
改进前20.165;20.463;20.383
效率提升28.1%
附:改进1的代码(改进2与改进1代码几乎相同,不同之处在于储存频繁项的数据类型,代码略)
附:改进2代码。