1 前言
关联规则反映一个事物与其他事物之间的相互依存性和关联性,是数据挖掘的一个重要技术,用于从大量数据中挖掘出有价值的数据项之间的相关关系。 本篇的Apriori算法主要是基于频繁集的关联分析。其主要目的就是为了寻找强关联规则。
常见的购物篮分析
通过观察顾客放人其购物篮中的不同商品之间的联系,分析顾客的购买习惯,了解哪些商品频繁地被顾客同时购买,这种关联的发现可以帮助零售商制定营销策略。
2 频繁项集评估标准
常用的频繁项集的评估标准有支持度,置信度和提升度三个
- 支持度:几个关联的数据在数据集中出现的次数占总数据集的比重
- 置信度:一个数据出现后,另一个数据出现的概率,或者说数据的条件概率。
- 提升度:表示含有Y的条件下,同时含有X的概率,与X总体发生的概率之比
Apriori算法----发现频繁项集的一种方法
原理:
- 如果一个项集是频繁项集,则它的所有子集都是频繁项集
- 如果一个集合不是频繁项集,则它的所有父集(超集)都不是频繁项集
关联分析的目标:
- 发现频繁项集:发现满足最小支持度的所有项集
- 发现关联规则:从频繁项集中提取所有高置信度的规则
3 Apriori算法采用了迭代的方法
- 先搜索出候选1项集及对应的支持度,剪枝去掉低于支持度的1项集,得到频繁1项集。
- 对剩下的频繁1项集进行连接,得到候选的频繁2项集,筛选去掉低于支持度的候选频繁2项集,得到真正的频繁二项集,
- 以此类推,迭代下去,直到无法找到频繁k+1项集为止,对应的频繁k项集的集合即为算法的输出结果
下图来自博客:https://www.cnblogs.com/pinard/p/6293298.html
算法流程
输入:数据集合D,支持度阈值αα
输出:最大的频繁k项集
1)扫描整个数据集,得到所有出现过的数据,作为候选频繁1项集。k=1,频繁0项集为空集。
2)挖掘频繁k项集
a) 扫描数据计算候选频繁k项集的支持度
b) 去除候选频繁k项集中支持度低于阈值的数据集,得到频繁k项集。如果得到的频繁k项集为空,则直接返回频繁k-1项集的集合作为算法结果,算法结束。如果得到的频繁k项集只有一项,则直接返回频繁k项集的集合作为算法结果,算法结束。
c) 基于频繁k项集,连接生成候选频繁k+1项集。
3) 令k=k+1,转入步骤2。
4 python 实现
class Apriori:
def __init__(self, minSupport, minConfidence):
# 最小支持度
self.minSupport = minSupport
# 最小置信度
self.minConfidence = minConfidence
self.data = self.loadData()
# 加载数据集
def loadData(self):
return [[1, 5], [2, 3, 4], [2, 3, 4, 5], [2, 3]]
# 生成项集C1,不包含项集中每个元素出现的次数
def createC1(self, data):
C1 = list() # C1为大小为1的项的集合
for items in data: # 遍历数据集
for item in items:
if [item] not in C1:
C1.append([item])
# map函数表示遍历C1中的每一个元素执行forzenset
# frozenset表示“冰冻”的集合,即不可改变
return list(map(frozenset, sorted(C1)))
# 该函数用于从候选项集Ck生成Lk,Lk表示满足最低支持度的元素集合
def scanD(self, Ck):
# Data表示数据列表的列表 [set([]), set([]), set([]), set([])]
Data = list(map(set, self.data))
CkCount = {}
# 统计Ck项集中每个元素出现的次数
for items in Data:
for one in Ck:
# issubset:表示如果集合one中的每一元素都在items中则返回true
if one.issubset(items):
CkCount.setdefault(one, 0)
CkCount[one] += 1
numItems = len(list(Data)) # 数据条数
Lk = [] # 初始化符合支持度的项集
supportData = {} # 初始化所有符合条件的项集及对应的支持度
for key in CkCount:
# 计算每个项集的支持度,如果满足条件则把该项集加入到Lk列表中
support = CkCount[key] * 1.0 / numItems
if support >= self.minSupport:
Lk.insert(0, key)
# 构建支持的项集的字典
supportData[key] = support
return Lk, supportData
# generateNewCk的输人参数为频繁项集列表Lk与项集元素个数k,输出为Ck
def generateNewCk(self, Lk, k):
nextLk = []
lenLk = len(Lk)
# 若两个项集的长度为k-1,则必须前k-2项相同才可连接,即求并集,所以[:k-2]的实际作用为取列表的前k-1个元素
for i in range(lenLk):
for j in range(i + 1, lenLk):
# 前k-2项相同时合并两个集合
L1 = list(Lk[i])[: k - 2]
L2 = list(Lk[j])[: k - 2]
if sorted(L1) == sorted(L2):
nextLk.append(Lk[i] | Lk[j])
return nextLk
# 生成频繁项集
def gengrateLK(self):
# 构建候选项集C1
C1 = self.createC1(self.data)
L1, supportData = self.scanD(C1)
L = [L1]
k = 2
while len(L[k - 2]) > 0:
# 组合项集Lk中的元素,声新的候选项集Ck
Ck = self.generateNewCk(L[k - 2], k)
Lk, supK = self.scanD(Ck)
supportData.update(supK)
L.append(Lk)
k += 1
return L, supportData
# 生成关联规则
def generateRules(self, L, supportData):
ruleResult = [] # 最终记录的关联规则结果
for i in range(1, len(L)):
for ck in L[i]:
Cks = [frozenset([item]) for item in ck]
# 频繁项集中有三个及以上元素的集合
self.rulesOfMore(ck, Cks, supportData, ruleResult)
return ruleResult
# 频繁项集只有两个元素
def rulesOfTwo(self, ck, Cks, supportData, ruleResult):
prunedH = []
for oneCk in Cks:
# 计算置信度
conf = supportData[ck] / supportData[ck - oneCk]
if conf >= self.minConfidence:
print(ck - oneCk, "-->", oneCk, "Confidence is:", conf)
ruleResult.append((ck - oneCk, oneCk, conf))
prunedH.append(oneCk)
return prunedH
# 频繁项集中有三个及以上元素的集合,递归生成关联规则
def rulesOfMore(self, ck, Cks, supportData, ruleResult):
m = len(Cks[0])
while len(ck) > m:
Cks = self.rulesOfTwo(ck, Cks, supportData, ruleResult)
if len(Cks) > 1:
Cks = self.generateNewCk(Cks, m + 1)
m += 1
else:
break
if __name__ == "__main__":
apriori = Apriori(minSupport=0.5, minConfidence=0.6)
L, supportData = apriori.gengrateLK()
for one in L:
print("项数为 %s 的频繁项集:" % (L.index(one) + 1), one)
print("supportData:", supportData)
print("minConf=0.6时:")
rules = apriori.generateRules(L, supportData)