关联规则(Association Rules)学习

关联规则(Association Rules)是反映一个事物与其他事物之间的相互依存性和关联性,是数据挖掘的一个重要技术,用于从大量数据中挖掘出有价值的数据项之间的相关关系。

常见的购物篮分析

该过程通过发现顾客放人其购物篮中的不同商品之间的联系,分析顾客的购买习惯。通过了解哪些商品频繁地被顾客同时购买,这种关联的发现可以帮助零售商制定营销策略。其他的应用还包括价目表设计、商品促销、商品的排放和基于购买模式的顾客划分。

可从数据库中关联分析出形如“由于某些事件的发生而引起另外一些事件的发生”之类的规则


频繁项集评估标准

常用的频繁项集的评估标准有支持度,置信度和提升度三个

  • 支持度:几个关联的数据在数据集中出现的次数占总数据集的比重

  • 置信度:一个数据出现后,另一个数据出现的概率,或者说数据的条件概率。

  • 提升度:表示含有Y的条件下,同时含有X的概率,与X总体发生的概率之比

 


Apriori算法----发现频繁项集的一种方法

原理:如果一个项集是频繁项集,则它的所有子集都是频繁项集

           如果一个集合不是频繁项集,则它的所有父集(超集)都不是频繁项集

关联分析的目标:

  • 发现频繁项集:发现满足最小支持度的所有项集
  • 发现关联规则:从频繁项集中提取所有高置信度的规则

 

Apriori算法采用了迭代的方法

  1. 先搜索出候选1项集及对应的支持度,剪枝去掉低于支持度的1项集,得到频繁1项集。
  2. 对剩下的频繁1项集进行连接,得到候选的频繁2项集,筛选去掉低于支持度的候选频繁2项集,得到真正的频繁二项集,
  3. 以此类推,迭代下去,直到无法找到频繁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。


代码实现

# Apriori算法
"""
由于Apriori算法假定项集中的项是按字典序排序的,而集合本身是无序的,所以我们在必要时需要进行set和list的转换;
由于要使用字典(support_data)记录项集的支持度,需要用项集作为key,而可变集合无法作为字典的key,因此在合适时机应将项集转为固定集合frozenset。
支持度
置信度

"""


class apriori_algorithm:

    # 算法初始化
    def __init__(self, minSupport, dataSet):
        self.minSupport = minSupport  # 最小支持度
        self.dataSet = dataSet  # 数据集

    # 加载数据集
    def loaddata(self):
        return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

    # 生成单个物品的项集列表
    def generateC1(self, dataSet):
        C1 = []  # 用于存放生成的单个物品的项集列表
        # 遍历数据集
        for data in dataSet:
            for item in data:
                if [item] not in C1:
                    C1.append([item])
        C1.sort()
        return C1

    # 遍历数据集,和Ck对比,计数
    def generateLk_by_Ck(self, dataSet, Ck, minSupport, support_data):
        """
           Generate Lk by executing a delete policy from Ck.
           Args:
               data_set: 数据集
               Ck: A set which contains all all frequent candidate k-itemsets.
               min_support: The minimum support.
               support_data: A dictionary. The key is frequent itemset and the value is support.
           Returns:
               Lk: A set which contains all all frequent k-itemsets.
           """
        D = map(set, dataSet)
        C = map(frozenset, Ck)
        C1 = list(C)  # 关于map对象的遍历,在内循环中遍历完最后一个元素后,再次访问时会放回空列表,所以外循环第二次进入的时候是空的,需要将其转为list处理
        countData = dict()
        for d in D:  # set遍历
            for c in C1:
                if c.issubset(d):  # 子集判断,并非元素判断
                    if c not in countData.keys():  # 将集合作为字典的键使用,c为[]型
                        countData[c] = 1

                    else:
                        countData[c] += 1

        numItems = float(len(list(dataSet)))
        returnList = []
        supportData = dict()
        # 遍历前面得到的计数字典
        for key in countData:
            support = countData[key] / numItems
            if support >= minSupport:
                returnList.insert(0, key)  # insert() 函数用于将指定对象插入列表的指定位置
                support_data[key] = support

        return returnList

    def generate_L(self, dataSet, k, min_support):
        """
           Generate all frequent itemsets.
           Args:
               data_set:数据集
               k: 频繁项集中含有的最多的元素
               min_support: 最小支持度
           Returns:
               L: 出现的所有频繁项集
               support_data: 每个频繁项集对应的支持度
           """
        support_data = {}
        C1 = self.generateC1(dataSet)
        L1 = self.generateLk_by_Ck(dataSet, C1, min_support, support_data)
        Lksub1 = L1.copy()

        L = []
        L.append(Lksub1)

        for i in range(2, k + 1):
            Ci = self.generateCK(Lksub1, i)
            Li = self.generateLk_by_Ck(dataSet, Ci, min_support, support_data)
            Lksub1 = Li.copy()
            L.append(Lksub1)
        return L, support_data

    # generateCK 候选频繁项集产生   参数 Lk频繁项集,k:项集元素个数
    def generateCK(self, Lk, k):
        Ck = set()
        len_Lk = len(list(Lk))
        list_Lk = list(Lk)
        for i in range(len_Lk):
            for j in range(1, len_Lk):
                l1 = list(list_Lk[i])
                l2 = list(list_Lk[j])
                l1.sort()
                l2.sort()
                if l1[0:k - 2] == l2[0:k - 2]:
                    Ck_item = list_Lk[i] | list_Lk[j]
                    if self.isCk(Ck_item, list_Lk):
                        Ck.add(Ck_item)
                    # Ck.add(Ck_item)
        return Ck

    # 频繁项集判断

    def isCk(self, Ck_item, list_Lk):
        for item in Ck_item:
            sub_Ck = Ck_item - frozenset([item])
            if sub_Ck not in list_Lk:
                return False
        return True

    # 生成关联规则
    def generate_big_rules(self, L, support_data, min_conf):
        """
        Generate big rules from frequent itemsets.
        Args:
            L: 所有频繁项集的列表
            support_data: 每个频繁项集对应的支持度
            min_conf: 最小可信度

        """
        big_rule_list = []
        sub_set_list = []
        for i in range(0, len(L)):
            for freq_set in L[i]:
                for sub_set in sub_set_list:
                    if sub_set.issubset(freq_set):
                        conf = support_data[freq_set] / support_data[freq_set - sub_set]
                        big_rule = (freq_set - sub_set, sub_set, conf)

                        if conf >= min_conf and big_rule not in big_rule_list:
                            print(freq_set - sub_set, " => ", sub_set, "conf: ", conf)
                            big_rule_list.append(big_rule)
                sub_set_list.append(freq_set)
        return big_rule_list


if __name__ == '__main__':
    minS = 0.5
    dataSet = [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
    apriori = apriori_algorithm(minSupport=minS, dataSet=dataSet)

    L, support_data = apriori.generate_L(dataSet, 3, minS)

    print(L)
    print(support_data)
    big_rule_list = apriori.generate_big_rules(L, support_data, 0.7)

结果:

所有的频繁项集L:

[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], [frozenset({2, 5}), frozenset({2, 3}), frozenset({3, 5}), frozenset({1, 3})], [frozenset({2, 3, 5})]]
所有频繁项集对应的支持度:

{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({1, 3}): 0.5, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({2, 3, 5}): 0.5}
生成关联规则:

frozenset({2})  =>  frozenset({5}) conf:  1.0
frozenset({5})  =>  frozenset({2}) conf:  1.0
frozenset({1})  =>  frozenset({3}) conf:  1.0
frozenset({2, 3})  =>  frozenset({5}) conf:  1.0
frozenset({3, 5})  =>  frozenset({2}) conf:  1.0

 

参考文献:

https://www.jianshu.com/p/469dff109fae

https://www.cnblogs.com/pinard/p/6293298.html,

https://www.cnblogs.com/llhthinker/p/6719779.html

  • 32
    点赞
  • 216
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

君子慎独_诚意

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值