关联分析——频繁项集的产生之Apriori算法
频繁项集的产生—Apriori算法
Apriori算法用于从数据集中提取频繁项集,以购物篮事务为例说明其过程:

提取频繁项集的过程如下:

Apriori算法的伪码如下:


Apriori算法的Python实现
给出数据集:
data = [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
提取1-项集
# 生成候选1-项集
def createC1(data):
c1 = []
for task in data:
for item in task:
if [item] not in c1:
c1.append([item])
# 排序是因为之后生产频繁k-项集是采用F(k-1)*F(k-1)方法
c1.sort()
# frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。
return list(map(frozenset, c1))
# 候选1-项集的结果如下
c1 = createC1(data)
c1
[frozenset({1}),
frozenset({2}),
frozenset({3}),
frozenset({4}),
frozenset({5})]
提取频繁k-项集
基于支持度的剪枝原理可用下图表示:

其原理在于如果一个项集是频繁的,则它的所有子集一定也是频繁的。根据逆否命题可得:如果一个项集的某个子集是非频繁的,则该项集一定是非频繁的。
# 提取频繁k-项集
def scanData(data, C_k, minSupport):
# 记录候选k-项集中项的支持度计数
ssCnt = {}
for task in data:
for can in C_k:
if can.issubset(task):
ssCnt[can] = ssCnt.get(can, 0) + 1
# 根据最小支持度计数提取频繁项集
retlist = []
F_k = {}
for key in ssCnt:
support = ssCnt[key] / len(data)
if support >= minSupport:
retlist.insert(0, key)
F_k[key] = support
return retlist, F_k
# F1_l记录频繁1-项集
# F_1记录频繁1-项集中各项集的支持度
F1_l, F_1 = scanData(data, c1, 0.5)
print(F1_l)
[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})]
print(F_1)
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({2}): 0.75, frozenset({5}): 0.75}
对应伪码的第2步和第12步。
生成候选k-项集
生成候选k-项集采用F(k-1) * F(k-1)方法,其原理如下:

# 采用F(k-1)*F(k-1)法:通过频繁项集列表F_k-1生成候选项集列表C_k
def aprioriGen(F_l, k):
C_l = []
for i in range(len(F_l)-1):
for j in range(i+1, len(F_l)):
# 对于频繁k-1项集合并规则为:前k-2项相同第k-1项不同
# 提取频繁k-1项集的前k-2项
l1 = list(F_l[i])[:k-2]
l2 = list(F_l[j])[:k-2]
l1.sort()
l2.sort()
if l1 == l2:
C_l.append(F_l[i] | F_l[j])
return C_l
C2_l = aprioriGen(F1_l, 2)
C2_l
[frozenset({2, 5}),
frozenset({3, 5}),
frozenset({1, 5}),
frozenset({2, 3}),
frozenset({1, 2}),
frozenset({1, 3})]
对应伪码的第5步。
Apriori算法
def apriori(data, minsupport):
# 生成候选1-项集
C1 = createC1(data)
# 提取频繁1-项集
F1_l, F1 = scanData(data, C1, minsupport)
# 返回频繁项集和频繁项集对应的支持度
L = [F1_l]
F = F1
# 逐层迭代,直到不再生成新的频繁项集
k = 2
while len(L[k-2]) > 0:
# 根据频繁k-1项集生成候选k-项集
Ck_l = aprioriGen(L[k-2], k)
# 从候选K-项集中提取频繁k-项集
Fk_l, Fk = scanData(data, Ck_l, minsupport)
L.append(Fk_l)
F.update(Fk)
k += 1
return L, F
L, F = apriori(data, 0.2)
# 频繁项集
print(L)
[[frozenset({5}), frozenset({2}), frozenset({4}), frozenset({3}), frozenset({1})], [frozenset({1, 2}), frozenset({1, 5}), frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3}), frozenset({1, 4}), frozenset({3, 4})], [frozenset({1, 3, 5}), frozenset({1, 2, 3}), frozenset({1, 2, 5}), frozenset({2, 3, 5}), frozenset({1, 3, 4})], [frozenset({1, 2, 3, 5})], []]
# 频繁项集何其对应的支持度
print(F)
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({3, 4}): 0.25, frozenset({1, 4}): 0.25, frozenset({1, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({1, 5}): 0.25, frozenset({1, 2}): 0.25, frozenset({1, 3, 4}): 0.25, frozenset({2, 3, 5}): 0.5, frozenset({1, 2, 5}): 0.25, frozenset({1, 2, 3}): 0.25, frozenset({1, 3, 5}): 0.25, frozenset({1, 2, 3, 5}): 0.25}
封装
class Apriori:
def __init__(self, minsupport):
self.minsupport = minsupport
def createC1(self, data):
c1 = []
for task in data:
for item in task:
if [item] not in c1:
c1.append([item])
# 排序是因为之后生产频繁k-项集是采用F(k-1)*F(k-1)方法
c1.sort()
# frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。
return list(map(frozenset, c1))
def scanData(self, data, C_k, minSupport):
# 记录候选k-项集中项的支持度计数
ssCnt = {}
for task in data:
for can in C_k:
if can.issubset(task):
ssCnt[can] = ssCnt.get(can, 0) + 1
# 根据最小支持度计数提取频繁项集
retlist = []
F_k = {}
for key in ssCnt:
support = ssCnt[key] / len(data)
if support >= minSupport:
retlist.insert(0, key)
F_k[key] = support
return retlist, F_k
def aprioriGen(self, F_l, k):
C_l = []
for i in range(len(F_l)-1):
for j in range(i+1, len(F_l)):
# 对于频繁k-1项集合并规则为:前k-2项相同第k-1项不同
# 提取频繁k-1项集的前k-2项
l1 = list(F_l[i])[:k-2]
l2 = list(F_l[j])[:k-2]
l1.sort()
l2.sort()
if l1 == l2:
C_l.append(F_l[i] | F_l[j])
return C_l
def apriori(self, data):
minsupport = self.minsupport
# 生成候选1-项集
C1 = self.createC1(data)
# 提取频繁1-项集
F1_l, F1 = self.scanData(data, C1, minsupport)
# 返回频繁项集和频繁项集对应的支持度
L = [F1_l]
F = F1
# 逐层迭代,直到不再生成新的频繁项集
k = 2
while len(L[k-2]) > 0:
# 根据频繁k-1项集生成候选k-项集
Ck_l = self.aprioriGen(L[k-2], k)
# 从候选K-项集中提取频繁k-项集
Fk_l, Fk = self.scanData(data, Ck_l, minsupport)
L.append(Fk_l)
F.update(Fk)
k += 1
return L, F
Apriori算法是一种经典的数据挖掘算法,用于从交易数据中发现频繁项集。该算法通过提取1-项集,生成候选k-项集并进行频繁项集的迭代查找,基于支持度进行剪枝。文章详细阐述了Apriori的工作流程,并给出了Python实现的概要。
1万+





