Apriori

1 关联规则挖掘

1.1 理论定义

  • 支持度(support):数据集中包含该项集的数据所占数据集的比例,度量一个集合在原始数据中出现的频率

  • 置信度(confidence):针对关联规则定义如 c o n f i d e n t ( A → B ) = s u p p o r t ( A ∪ B ) s u p p o r t ( A ) confident(A\rightarrow B) = \frac{support(A \cup B)}{support(A)} confident(AB)=support(A)support(AB),可以理解为在事件A发生的条件下,B发生的概率。

  • 频繁项集:经常出现在一块的的集合。

  • 关联规则:形如 A → B A \rightarrow B AB,当 c o n f i d e n t ( A → B ) confident(A \rightarrow B) confident(AB)较高时,表明事件A发生的同时,往往伴随着事件B的发生。

例,现有超市购物篮数据集如下

超市购物篮数据

表1:超市购物篮数据

表中的每一行代表一次购买清单,清单中的每一个商品称为,清单中任意的组合称之为项集,清单中所有的集合称为总项集。上表中的总项集为:S = {牛奶,面包,尿布,啤酒,鸡蛋,可乐}。

根据支持度和置信度的定义有:
s u p p o r t ( 啤 酒 ) = 3 5 = 0.6 support(啤酒)=\frac{3}{5}=0.6 support()=53=0.6

s u p p o r t ( 啤 酒 , 尿 布 ) = 3 5 = 0.6 support(啤酒,尿布) = \frac{3}{5} = 0.6 support(尿)=53=0.6

c o n f i d e n t ( 啤 酒 → 尿 布 ) = s u p p o r t ( 啤 酒 , 尿 布 ) s u p p o r t ( 啤 酒 ) = 0.6 0.6 = 1 confident(啤酒 \rightarrow 尿布) = \frac{support(啤酒,尿布)}{support(啤酒)}=\frac{0.6}{0.6}=1 confident(尿)=support()support(尿)=0.60.6=1

1.2 现实意义

支持度越高表明出现越频繁,即对于商品来讲越受欢迎,销量高。

置信度越高表明在某出现的时候,往往伴随则另一些项的出现,如上述示例中尿布的购买往往伴随着啤酒的购买。

对于超市经营者,如果能够知道支持度高的商品即销量高的商品,那么可以增加对这类商品的投入。更进一步,如果经营者知道有哪些商品与销量高的商品经常一起购买,那么经营者就可以考虑缩短这些商品在超市中的物理距离,可以摆放临近的货架,对于互补品也可以考虑捆绑销售的促销策略,以期获得更高的收益。

1.3 算法实现

对于一个包含 n n n个项的总项集来讲,它的子项集有 2 n − 1 2^n-1 2n1个(不考虑空项集),显然并不是每一个子项集都有意义,同样并不是每一个挖掘到的规则都有意义。那么如何判断挖掘到的子项集或者规则是否意义?

实际中,较为普遍地是通过设定支持度阈值来区分频繁项集非频繁项集置信度阈值区分强关联规则弱关联规则

关联规则的目标分为发现频繁项集(满足最小支持度要求的项集)和发现关联规则(满足最小置信度要求的规则)两部分。关联规则的发现建立在频繁项集的基础上,因此下面我们首先介绍Apriori算法。

1.3.1 Apriori算法

Apriori算法伪代码

Apriori算法

以表1超市购物篮数据为例进行频繁项集的挖掘,设定支持度阈值 α = 0.6 \alpha=0.6 α=0.6。具体挖掘流程如下图所示:

频繁项集挖掘流程图
在支持度阈值 α = 0.6 \alpha=0.6 α=0.6时,无频繁3项集,该数据集的最大频繁K项集为频繁2项集即:F2。

注意:由频繁2项集F2生成候选频繁3项集时无{牛奶,面包,啤酒},{牛奶,尿布,啤酒},{面包,尿布,啤酒}这三种组合,是因为{牛奶,啤酒},{面包,啤酒}不是频繁项集,详见Apriori定律。

1.3.2 Apriori定律

如果某个项集是频繁的,那么它的所有子集也是频繁的(例:如果{B,C}为频繁项集,那么{B},{C}也一定为频繁项集);

如果某个项集是非频繁的,那么它的所有超集(包含非频繁项集的超集)也是非频繁的(例:如果{A,B}是非频繁的,那么{A,B,C},{A,B,C,D}也一定是非频繁的)。

1.3.3 关联规则的挖掘

关联规则建立在频繁项集的基础之上。

对给定频繁项集 I I I进行关联规则挖掘算法流程图如下:

关联规则挖掘

注:如果频繁项集内的某条规则并不满足最小置信度要求,那么该规则的所有子集也不会满足最小置信度的要求

简单证明:对于频繁项集 I I I,关联规则 ( S − > I − S ) (S->I-S) (S>IS)的置信度为
c o n f i d e n t ( S → I − S ) = s u p p o r t ( I ) s u p p o r t ( S ) confident(S\rightarrow I-S) = \frac{support(I)}{support(S)} confident(SIS)=support(S)support(I)
在给定频繁项集 I I I和最小置信度阈值 β \beta β时,关联规则 ( S − > I − S ) (S->I-S) (S>IS)能否满足最小置信度要求,仅取决于 S S S的支持度大小。 s u p p o r t ( S ) support(S) support(S)越小, c o n f i d e n t ( S − > I − S ) confident(S->I-S) confident(S>IS)就越大。

由Apriori定律知: s u p p o r t ( S ) ≤ s u p p o r t ( S 的 子 集 ) support(S) \le support(S的子集) support(S)support(S),所以当 ( S − > I − S ) (S->I-S) (S>IS)不满足最小置信度阈值要求时,在当前频繁项集 I I I中,所有 S S S的子集 R R R,形成的 ( R − > I − R ) (R->I-R) (R>IR)均不满足最小置信度阈值要求。

1.4 代码实现

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    : Apriori.py
@Time    : 2022/03/15 19:51:22
@Author  : yy
@Desc    : Apriori关联规则
'''



class Apriori:
    def __init__(self,dataSets,k,min_support,min_Conf) -> None:
        self.dataSets = [set(record) for record in dataSets]
        self.k = k      #频繁项集中的元素个数
        self.min_num = round(min_support*len(dataSets)) #最小支持度*样本数据量
        self.min_Conf = min_Conf        #最小置信度

    def createC1(self):
        """输出候选1项集
        Returns:
            C1          候选1项集[集合,计数]
        """
        new_data = []
        for record in self.dataSets:
            new_data.extend(list(record))
        items1 = set(new_data) 
        C1 = []         #候选项集
        for item in items1:
            C1.append([{item},new_data.count(item)])
        return C1

    def frequent(self,C):
        """从候选k项集C中挖掘频繁k项集
        Args:
            C           候选k项集,[集合,计数]
        Returns:
            L           频繁k项集[集合,计数]
        """
        L = []      
        for row in C:
            if row[-1] >= self.min_num:
                L.append(row)
        return L


    def createC(self,L,L1):
        """计算k频繁项集候选集
        Args:
            L            k-1频繁项集[集合,计数]
            L1           1频繁项集[集合,计数]
            dataSetsT    样本记录转换为set后的数据集[set,set,...]
        Returns:
            Ck            k频繁项集候选集[集合,计数],计数可能为0
        """
        #记录所有可能的候选项集
        C0 = []
        for items in L:
            for item in L1:
                if not item[0].issubset(items[0]):
                    newitems0 = items[0].copy()
                    newitems0.update(item[0])
                    if newitems0 not in C0:
                        C0.append(newitems0)

        Ck = [ [newitems,0] for newitems in C0]
        for row in Ck:
            #计算频繁项集候选集在样本数据中出现的次数,显然会有可能出现后选项集计数为0的情况
            for record in self.dataSets:
                if row[0].issubset(record):
                    row[-1] += 1
        return Ck   

    def aprioriK(self):
        """在给定样本数据集和最小支持度的情况下,输出k频繁项集
        Returns:
            L   k频繁项集
        """
        #初始化1频繁项集
        C1 = self.createC1()
        L1 = self.frequent(C1)
        L = L1.copy()
        K = self.k
        while K-1:
            C = self.createC(L,L1)
            L = self.frequent(C)
            K -= 1
        return L    

    def calcConf(self,I,S):
        """计算S->I-S的置信度
        Args:
            I           频繁项集[集合,计数]
            S           I中集合的非空真子集
        Returns:
            conf        S->I-S的置信度
        """
        Scount = 0
        for items in self.dataSets:
            if S.issubset(items):
                Scount += 1
        conf = I[-1] / Scount

        return  conf

    def generateRule(self,frequentSet):
        """生成频繁项集的非空子集,并根据最小置信度筛选出当前频繁项集中的规则
        Args:
            frequentSet     频繁项集[集合,计数]
        """
        
        associationRules = []        #存储子集
        I = list(frequentSet[0])
        #集合子集的生成思想,集合元素存在在于不在子集中两种状态,可以用0-1二进制表示。
        for i in range(1 << len(I)):    #按位左移,如1<<2-->则为4,全为0的情况不考虑
            S = set()
            for j in range(len(I)):
                if i & (1 << j):    #每个数用&操作判断该位上是否有1,参与运算的两个值,如果两个相应位都为1,则该位的结果为1
                    S.add(I[j])
            if len(S) == 0 or len(S) == len(I):
                continue
            conf = self.calcConf(frequentSet,S)
            if conf >= self.min_Conf:
                associationRules.append(['{}-->{}'.format(S,frequentSet[0]-S),"%.2f"%conf])
            
        return associationRules

    def aprioriMining(self):
        L = self.aprioriK()    #频繁项集
        rules = []                              #挖掘出的关联规则
        for frequentSet in L:
            rules.extend(self.generateRule(frequentSet))
        return rules

def loadDataSet(flag=1):
    if flag == 1:
        dataSets = [['A', 'C', 'D'], ['B', 'C', 'E'], ['A', 'B', 'C', 'E'], ['B', 'E']]
    else:
        dataSets = [['牛奶','面包'],['面包','尿布','啤酒','鸡蛋'],['牛奶','尿布','啤酒','可乐'],['面包','牛奶','尿布','啤酒'],['面包','牛奶','尿布','可乐']]
    return dataSets

def main():
    dataSets = loadDataSet()
    k = 3
    min_support = 0.5
    min_Conf = 0.5
    model = Apriori(dataSets,k,min_support,min_Conf)
    print(model.aprioriMining())

if __name__ == '__main__':
    main()

1.5 参考链接

https://www.cnblogs.com/fengfenggirl/p/associate_apriori.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值