Apriori 算法使用了逐层搜索的迭代方法,即用 k-项集探索(k+1)-项集。为提高按层次搜索并产生相应频繁项集的处理效率,Apriori 算法利用了一个重要性质,该性质还能有效缩小频繁项集的搜索空间。
Apriori 性质:一个频繁项集的所有非空子集也必须是频繁项集。即假如项集 A 不满足最小支持度阈值,即 A 不是频繁的,则如果将项集 B 添加到项集 A 中,那么新项集(AUB)也不可能是频繁的。
Apriori 算法简单来说主要有以下几个步骤:
1)通过单遍扫描数据集,确定每个项的支持度。一旦完成这一步,就可得到所有频繁 1-项集的集合 F1。
2)使用上一次迭代发现的频繁(k-1)-项集,产生新的候选k-项集。
3)为了对候选项集的支持度计数,再次扫描一遍数据库,使用子集函数确定包含在每一个交易 t 中的所有候选 k-项集。
4)计算候选项集的支持度计数后,算法将删除支持度计数小于支持度阈值的所有候选项集。
5)重复步骤(2)、(3)、(4),当没有新的频繁项集产生时,算法结束。Apriori 算法是个逐层算法,它使用“产生——测试”策略来发现频繁项集。在由(k-1)-项集产生 k-项集的过程中“新产生的 k-项集先要确定它的所有的(k-1)-项真子集都是频繁的,如果有一个不是频繁的,那么它可以从当前的候选项集中去掉。
代码如下:
import time
def load_data():
f = open(r'retail.txt', encoding='utf-8')
data = []
for line in f:
records = line.split()
every_line = []
for item in records:
every_line.append(int(item))
data.append(every_line)
return data
def create_l1(data, min_sup):
sscnt = {}
for i in data:
for j in i:
if frozenset({j}) not in sscnt:
sscnt[frozenset({j})] = 1
else:
sscnt[frozenset({j})] += 1
num_items = float(len(data))
l1 = []
sup_data = {}
for k in sscnt:
support = sscnt[k] / num_items
if support >= min_sup:
l1.append(k)
sup_data[k] = support
return l1, sup_data
# 从候选K项集到频繁K项集(支持度计算)
def ck_to_lk(data, ck, min_sup):
sscnt = {}
for i in data:
for j in ck:
if j.issubset(i): # 判断j是否i的子集,返回的足布尔型数据
if j not in sscnt:
sscnt[j] = 1
else:
sscnt[j] += 1
num_items = float(len(data))
lk = [] # 频繁项集
sup_data = {}
for k in sscnt:
support = sscnt[k] / num_items
if support >= min_sup:
lk.append(k)
sup_data[k] = support
return lk, sup_data
# 剪枝
def lk_to_ckk(lk, k):
ck = []
len_lk = len(lk)
for i in range(len_lk):
for j in range(i+1, len_lk):
l1 = list(lk[i])[:k - 2]
l2 = list(lk[j])[:k - 2]
l1.sort()
l2.sort()
if l1 == l2:
a = lk[i] | lk[j]
if len(a) == k:
ck.append(lk[i] | lk[j])
return ck
def apriori(data, min_sup=0.05):
l1, sup_data = create_l1(data, min_sup)
l = [l1]
k = 2
while len(l[k-2]) > 0:
ck = lk_to_ckk(l[k-2], k)
lk, supk = ck_to_lk(data, ck, min_sup)
sup_data.update(supk)
l.append(lk)
k += 1
print(sup_data)
print(len(sup_data))
return l, sup_data
if __name__ == '__main__':
start = time.perf_counter()
dataSet = load_data()
L, sup_data = apriori(dataSet)
end = time.perf_counter()
print('Running time: %s Seconds' % (end - start))
数据集如图:
支持度=0.2时,运行结果:
支持度=0.02时,运行结果:
支持度=0.01时,运行结果: