简介
用户一次购买的过程其实包含了许多机器学习的应用,包括物品的展示方式、购物后优惠卷的提供等等。通过查看哪些商品经常在一起被购买,帮助了解用户的购买行为,这种从大规模数据集中寻找物品间的隐含关系被称作关联分析或者关联规则学习。而apriori就是对其思想的算法实现。
关联分析
一种在大规模数据中寻找物品关系的过程
步骤:
根据支持度找出所有的频繁项集
依据置信度产生强关联规则
关联规则:暗示物品之间可能存在很强的关系({牛奶}->{面包}购买牛奶的人再购买面包),而关联规则就是我们需要的结果-物品间的强关系,条件:规则的置信度大于最小置信度
置信度:是针对关联规则来定义的。拿{牛奶}->{面包}举例子,这条规则代表如果买了牛奶,就有可能还会买面包。在概率论里的意思就是当事件发生X的时候,计算发生Y的概率,也就是条件概率p(y|x) = p(xy)/p(x),也就是xy同时发生的概率/x发生的概率。用下图举例子就是用户在购买牛奶的时候再次购买面包的概率是:用户同时购买牛奶和面包的概率,除用户仅购买的面包的概率。
最小置信度:置信度的阀值
频繁项集:经常出现在一起的物品的集合({牛奶,面包}),条件:支持度大于最小支持度
支持度:数据集中包含该项集的记录所占的比例。下图来说,{牛奶,面包}有2条记录包含,所以这个项集的支持度就是2/5。支持度代表项集出现的概率,概率的较低的数据不具备代表性,将被过滤。
最小支持度:支持度的阀值
用下面这个表格解释(1表示购买,0表示未购买)
transaction ID | 牛奶 | 面包 | 黄油 | 啤酒 | 尿布 |
---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 |
2 | 0 | 0 | 1 | 0 | 0 |
3 | 0 | 0 | 0 | 1 | 1 |
4 | 1 | 1 | 1 | 0 | 0 |
5 | 1 | 0 | 0 | 1 | 1 |
Apriori原理
现在有了支持度、置信度,但是该如何高效的找出频繁项集呢?如图所示,假如现在我们需要找到{0,3}的支持度,需要先遍历所有交易的记录,如果记录包含这条项集则count+1,用count/记录总数得到支持度,若大于最小支持度则为频繁项集。
这只是其中的一组数据,图中有个4个商品,全部组合方式有15种,N种商品就会有2的N次方-1种组合方式,商品的增长会造成组合数的急剧上增,而且大多数是无效数据。
使用apriori减少生成的无效数据
apriori定理:
如果某个项集是频繁的,那么的他的子集也必然是频繁的。
相反,如果某个项集是非频繁的,那么他的超集也必然是非频繁的。
算法原理:
首先扫描数据集,生成单个物品的项集列表,计算每个项集的支持度,将哪些不满足最小支持度的项集过滤掉。得到一阶频繁项集,再对一阶频繁项集组合生成二阶候选项集,以此类推直到不能再生成项集或者,阶级为物品总数量。
查找频繁项集
扫描所有的记录:
扫描所有的候选项集:
如果候选项集时纪录的子集,增加候选项集的count,表明纪录包含该候选项集的个数
扫描所有的候选项集:
若候选项集的支持度大于最小支持度,则为频繁项集,保留
返回频繁项目集
完整的查找频繁项集:
当前频繁项集不为空
构建一个(k+1阶)组成的候选项集列表
判断每个项集是否频繁的
保留(k+1阶)频繁项集
如图查找频繁项目集全过程:
计算关联规则
从一个频繁项目集可以产生多少关联规则呢,用{0,1,2,3}这个项集来举例,如下图15种组合方式
类似查找频繁项集的原理,如果123->0小于最小置信度,那么该规则的所有子集也会小于最小置信度
123->0 的置信度 = p(0|123) = p(0123)/p(123)
23->01 的置信度 = p(23|01) = p(0123)/p(23)
13->02 的置信度 = p(02|13) = p(0123)/p(13)
12->03 的置信度 = p(03|12) = p(0123)/p(12)
若p(0123)/p(123)小于置信度则p(0123)/p(23)必然小于置信度,因为p(23)>=p(123)
所以根据这个原理减少频繁项集生成无用的关联规则,然而实现代码并没有这么写> <…
Apriori实现
查找频繁项集
def apriori(dataSet, minSupport=0.5):
largeSet = {} # 总的频繁项集
largeSupport = {} # 总的支持度
c1 = createC1(dataSet) # 创建一阶候选集
l1, supportData = scan(map(set, dataSet), c1, minSupport) # 扫描一阶频繁项集
k = 2 # 下一阶k值
currentLSet = l1 # 当前的频繁项集
while currentLSet:
largeSet[k - 2] = currentLSet # store 当前频繁项集
largeSupport = dict(largeSupport, **supportData) # store 当前支持度到支持度集合中
currentCSet = joinSet(currentLSet, k) # 获得k阶候选集
currentLSet, supportData = scan(dataSet, currentCSet, minSupport) # 扫描k阶候选集,得到频繁项集
k += 1
return largeSet, largeSupport
计算关联规则
def rules(largeSet,largeSupport,minConf = 0.5):
rules = []
for key,value in largeSet.items()[1:]: #从二阶频繁项集集合开始计算
for item in value : #遍历k阶的频繁项集
subsets = map(frozenset,subset(item)) #计算某个频繁项集的所有子项集
for element in subsets : #遍历所有子项集
remain = item.difference(element) #计算后置项
if(len(remain) > 0): #有后置项
confidence = largeSupport.get(item)/largeSupport.get(element) #计算关联关系置信度
if confidence > minConf:
rules.append((tuple(element),tuple(remain),confidence))
return rules
完整代码
https://github.com/whx4J8/machine-learn.git