Apriori算法
关联分析:
是一种在大规模数据集中寻找有趣关系的非监督学习算法。这种关系可以有两种形式:频繁项集或者关联规则。频繁项集是经常出现在一块的物品的集合;关联规则暗示两种物品之间可能存在很强的关系。
几个基本概念:
事务:每一天交易称为一个事务。
项:交易的每一个物品称为一个项;
项集:包含零个或多个项的集合叫做项集;
k-项集:包含k 个项的项集叫做 k-项集;
前件和后件:对于规则(尿布)–>(啤酒),(尿布)叫做前件,(啤酒)叫做后件;
频繁项集的评估标准
1.支持度
支持度就是几个关联的数据在数据集中出现的次数占总数据集的比重,或者说几个数据关联出现的概率。
如果有两个想分析关联性的数据X 和Y ,则对应的支持度为:
S
u
p
p
o
r
t
(
X
,
Y
)
=
P
(
X
Y
)
=
n
u
m
b
e
r
(
X
Y
)
n
u
m
(
A
l
l
S
a
m
p
l
e
s
)
Support(X,Y) = P(XY)= \frac{number(XY)}{num(AllSamples)}
Support(X,Y)=P(XY)=num(AllSamples)number(XY)
一般来说,支持度高的数据不一定构成频繁项集,但是支持度太低的数据肯定不构成频繁项集。另外,支持度是针对项集来说的,因此,可以定义一个最小支持度,而只保留满足最小支持度的项集,起到一个过滤项集的作用。
2.置信度
置信度体现了一个数据出现后,另一个数据出现的概率,或者说数据的条件概率,如果有两个分析关联性的数据X和Y,X对Y的置信度为:
C
o
n
f
e
r
e
n
c
e
(
X
−
>
Y
)
=
P
(
X
∣
Y
)
=
P
(
X
Y
)
/
P
(
Y
)
Conference(X->Y) = P(X|Y) = P(XY)/P(Y)
Conference(X−>Y)=P(X∣Y)=P(XY)/P(Y)
支持度是一种重要的度量,因为支持度很低的规则可能只是偶然出现,从商务角度分析,低支持度的规则多半是无意义的,因为对顾客很少同时购买的商品进行促销可能并无益处。因此,支持度通常用来删除那些无意义的规则。此外,支持度还具有一种期望的性质,可以用于关联规则的有效发现。
另一方面,置信度度量是通过规则进行推理具有可靠性。对于给定的规则X–>Y,置信度越高,Y在包含X的事务中出现的可能性就越大,置信度也可以估计Y 在给定X下的条件概率;
同时,应该小心解释关联分析的结果,由关联规则做出的推论并不必然蕴涵因果关系,它只表示规则前件和后件同时出现的一种概率。
3.提升度
提升度表示含有Y的条件下同时含有X的概率,与X总体发生的概率之比,也就是X对Y的提升度与X总体发生的概率纸币.即:
L
i
f
t
(
X
−
>
Y
)
=
P
(
X
∣
Y
)
/
P
(
X
)
=
C
o
n
f
e
r
e
n
c
e
(
X
−
>
Y
)
/
P
(
X
)
Lift(X->Y) = P(X|Y)/P(X) = Conference(X->Y)/P(X)
Lift(X−>Y)=P(X∣Y)/P(X)=Conference(X−>Y)/P(X)
提升度体现了X和Y之间的关联关系,提升度大于1则X<= Y是有效的强关联规则,提升度小于等于1则X <= Y的无效的强关联规则。特殊情况,如果X 和Y独立,则有Lift(X <= Y) = 1,因为此时P(X|Y) = P(X)。
一般情况下,要选择一个数据集合中的频繁数据集,则需要自定义评估标准,最常用的评估标准是用自定义的支持度,或者自定义支持度和置信度的一个组合;
关联规则的发现
给定事务的集合T,关联规则发现是指找出支持度大于等于minsup并且置信度大于等于minconf的所有规则,其中minsup和minconf是对应的支持度和置信度阈值。
挖掘关联规则的原始方法:计算每个可能规则的支持度和置信度。
从包含d个项的数据集提取的可能规则总数为:
R
=
3
d
−
2
d
+
1
+
1
R= 3^d - 2^{d+1} +1
R=3d−2d+1+1
常用的关联规则挖掘算法采用的策略是,将关联规则分解为如下两个主要的子任务:
1.频繁项集的产生
目标是发现满足最小支持度阈值的所有项集,这些项集称作频繁项集;
2.规则的产生
目标是从上一步发现的频繁项集中提取所有高置信度的规则,这些规则称作强规则;
降低产生频繁项集的计算复杂度:
1.减少候选项集的数目M
2.减少比较次数,替代将每个候选项集与每个事务相匹配,可以使用更高级的数据结构,或者存储候选项集或者压缩数据集,来减少比较次数;
Apriori算法原理
先验原理:如果一个项集是频繁的,则它的所有子集一定也是频繁的。
发现频繁项集
C1,C2,…分别表示1-项集,2-项集,…
L1,L2,…分别表示由K 个数据项的频繁项集;
Scan表示数据集扫描函数,该函数起到的作用是支持度过滤,满足最小支持度的项集才留下,不满足最小支持度的项集被过滤;
生成候选项集
数据集扫描的伪代码:
对数据集中的每条交易记录transaction
对每个候选项集can:
检查can是否是transaction的子集:
如果是,增加 can的计数
对每个候选项集:
如果支持度不低于最小值,则保留该项集
返回所有频繁项集列表
组织完整的Apriori算法
伪代码:
当集合中项的个数大于0时:
构建一个 k-项集组成的列表
检查数据确保每个项集都是频繁的
保留频繁项集并构建(k + 1) -项集组成列表
代码:
def loadDataset():
"""输入的数据集"""
dataSet = [[1, 3, 4], [2, 3, 4], [1, 2, 3, 4], [2, 3, 4, 5]]
return dataSet
def create(dataSet):
"""生成第一个候选集合C1
:param dataSet: 原始数据集
:return: frozenset形式的候选集合C1
"""
C1 = []
for transaction in dataSet:
# print(transaction)
for item in transaction:
# print(item)
if not {item} in C1:
# print({item})
C1.append({item})
# print(C1)
C1.sort()
# TODO list和map、frozenset函数含义???
# list将元组转化为列表
# map会根据提供的函数对指定序列做映射
# frozenset 返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。
return list(map(frozenset, C1))
def scanD(D, Ck, minSupport):
"""生成满足最小支持度的频繁项集L1
:param D: 原始数据集
:param Ck: 候选项集
:param minSupport:最小支持度
:return:retList:频繁项集
supportData:候选项集的支持度
"""
ssCnt = {}
for tid in D:
for can in Ck:
if can.issubset(tid):
if can not in ssCnt.keys(): # 判断can是否是tid的子集,返回的是布尔型数据 ssCnt[can] = 1
else:
ssCnt[can] += 1
numItem = float(len(D))
retList = []
supportData = {} # 候选集项Ck的支持度字典(key:候选项, value:支持度) for key in ssCnt:
support = ssCnt[key] / numItem
supportData[key] = support
if support >= minSupport:
retList.append(key)
return retList, supportData
def aprioriGen(Lk, k):
"""
:param Lk: 频繁项集
:param k: 项集元素个数
:return:
"""
Ck = []
lenlk = len(Lk)
for i in range(lenlk):
for j in range(i + 1, lenlk):
# 前 k - 2 个项相同时,将两个集合合并
L1 = list(Lk[i])[:k-2]
L1.sort()
L2 = list(Lk[j])[:k-2]
L2.sort()
if L1 == L2:
Ck.append(Lk[i] | Lk[j])
return Ck
def apriori(D, minsupport = 0.5):
C1 = create(D)
1, supportData = scanD(D, C1, minsupport)
L = [L1]
k = 2
while (len(L[k-2]) > 0):
Ck = aprioriGen(L[k-2], k)
# print("ck:", Ck)
Lk, supK = scanD(D, Ck, minsupport)
supportData.update(supK)
# print("lk:", lk)
L.append(Lk)
k += 1
return L, support
DatadataSet = loadDataset()
L, supportData = apriori(dataSet)
# print(L)
print(supportData)