数据挖掘实验——Apriori算法实现

一、实验目的

关联规则分析是数据挖掘中最活跃的研究方法之一,目的是在一个数据集中找出各项之间的关联关系,而这种关系并没有在数据中直接表示出来。本实验主要目的是培养学生能够运用Apriori算法数据挖掘方法进行数据挖掘。

二、实验要求

学习掌握数据挖掘方法中的Apriori算法。

三、实验内容

就餐饮企业而言,经常会碰到这样的问题:客户在餐厅点餐时,面对菜单中大量的菜品信息,往往无法迅速找到满意的菜品,既增加了点菜的时间,也降低了客户的就餐体验。实际上,菜品的合理搭配是有规律可循的:顾客的饮食习惯、菜品的荤素和口味,有些菜品之间是相互关联的,而有些菜品之间是对立或竞争关系(负关联)。这些规律都隐藏在大量的历史菜单数据中,如果能够通过数据挖掘发现客户点餐的规则,就可以快速识别客户的口味,当他下了某个菜品的订单时推荐相关联的菜品,引导客户消费,提高顾客的就餐体验和餐饮企业的业绩水平。

根据下表给定的餐饮订单数据,使用下图Apriori算法挖掘其中的所有频繁项集和支持度,以及所有强关联规则和相应的支持度。

表1 餐饮订单数据

订单ID

菜品ID

001

健康麦香包,三丝炒河粉,翡翠蒸香茜饺

002

菜心粒咸骨粥,养颜红枣糕

003

菜心粒咸骨粥,三丝炒河粉

004

健康麦香包,菜心粒咸骨粥,三丝炒河粉,养颜红枣糕

005

健康麦香包,菜心粒咸骨粥

006

菜心粒咸骨粥,三丝炒河粉

007

健康麦香包,菜心粒咸骨粥

008

健康麦香包,菜心粒咸骨粥,三丝炒河粉,翡翠蒸香茜饺

009

健康麦香包,菜心粒咸骨粥,三丝炒河粉

010

健康麦香包,三丝炒河粉,翡翠蒸香茜饺

数据挖掘实验——Apriori算法实现_第1张图片
数据挖掘实验——Apriori算法实现_第2张图片

四、实验结果及分析

重新编辑菜品ID:1代表健康麦香包,2代表三丝炒河粉,3代表翡翠蒸香茜饺,4代表菜心粒咸骨粥,5代表养颜红枣糕,将原表格化为:

订单ID

菜品ID

001

1,2,3

002

4,5

003

4,2

004

1,4,2,5

005

1,4

006

4,2

007

1,4

008

1,4,2,3

009

1,4,2

010

1,2,3

  1. 代码部分

'''
Apriori算法,频繁项集算法
1代表健康麦香包,2代表三丝炒河粉,3代表翡翠蒸香茜饺,
4代表菜心粒咸骨粥,5代表养颜红枣糕
1,2,3
4,5
4,2
1,4,2,5
1,4
4,2
1,4
1,4,2,3
1,4,2
1,2,3
min_support = 2
'''


def item(dataset):  # 求第一次扫描数据库后的候选集
    c1 = []  # 存放候选集元素

    for x in dataset:  # 求这个数据库中出现了几个元素,然后返回
        for y in x:
            if [y] not in c1:
                c1.append([y])
    c1.sort()
    # print(c1)
    return c1


def get_frequent_item(dataset, c, min_support):
    cut_branch = {}  # 用来存放所有项集的支持度的字典
    for x in c:
        for y in dataset:
            if set(x).issubset(set(y)):  # 如果x不在y中,就把对应元素后面加 1
                cut_branch[tuple(x)] = \
                    cut_branch.get(tuple(x), 0) + 1
                # cut_branch[y] = new_cand.get(y, 0)表示如果字典里面没有想要的关键词,就返回0
    # print(cut_branch)

    Fk = []  # 支持度大于最小支持度的项集,即频繁项集
    sup_dataK = {}  #用来存放所有频繁项集的支持度的字典
    for i in cut_branch:
        if cut_branch[i] >= min_support:  # Apriori定律1  小于支持度,则就将它舍去,它的超集必然不是频繁项集
            Fk.append(list(i))
            sup_dataK[i] = cut_branch[i]
    # print(Fk)
    return Fk, sup_dataK


def get_candidate(Fk, K):  # 求第k次候选集
    ck = []  # 存放产生候选集

    for i in range(len(Fk)):
        for j in range(i + 1, len(Fk)):
            L1 = list(Fk[i])[:K - 2]
            L2 = list(Fk[j])[:K - 2]
            L1.sort()
            L2.sort()  # 先排序,在进行组合

            if L1 == L2:
                if K > 2:  # 第二次求候选集,不需要进行减枝,因为第一次候选集都是单元素,且已经减枝了,组合为双元素肯定不会出现不满足支持度的元素
                    new = list(set(Fk[i]) ^ set(Fk[j]))  # 集合运算 对称差集(含义,集合的元素在t或s中,但不会同时出现在二者中)
                    # new表示,这两个记录中,不同的元素集合
                    # 为什么要用new? 比如 1,2和1,3  两个合并成 1,2,3   我们知道1,2 和 1,3 一定是频繁项集,但 2,3呢,我们要判断2,3是否为频繁项集
                    # Apriori定律1 如果一个集合不是频繁项集,则它的所有超集都不是频繁项集
                else:
                    new = set()
                for x in Fk:
                    if set(new).issubset(set(x)) and list(
                            set(Fk[i]) | set(Fk[j])) not in ck:  # 减枝 new是 x 的子集,并且 还没有加入 ck 中
                        ck.append(list(set(Fk[i]) | set(Fk[j])))
    # print(ck)
    return ck


def Apriori(dataset, min_support=2):
    c1 = item(dataset)  # 返回一个二维列表,里面的每一个一维列表,都是第一次候选集的元素
    f1, sup_1 = get_frequent_item(dataset, c1, min_support)  # 求第一次候选集

    F = [f1]  # 将第一次候选集产生的频繁项集放入 F ,以后每次扫描产生的所有频繁项集都放入里面
    sup_data = sup_1  # 一个字典,里面存放所有产生的候选集,及其支持度

    K = 2  # 从第二个开始循环求解,先求候选集,在求频繁项集

    while (len(F[K - 2]) > 1):  # k-2是因为F是从0开始数的     #前一个的频繁项集个数在2个或2个以上,才继续循环,否则退出
        ck = get_candidate(F[K - 2], K)  # 求第k次候选集
        fk, sup_k = get_frequent_item(dataset, ck, min_support)  # 求第k次频繁项集

        F.append(fk)  # 把新产生的候选集加入F
        sup_data.update(sup_k)  # 字典更新,加入新得出的数据
        K += 1
    return F, sup_data  # 返回所有频繁项集, 以及存放频繁项集支持度的字典


if __name__ == '__main__':
    dataset = [[1,2,3],
               [4,5],
               [4,2],
               [1,4,2,5],
               [1,4],
               [4,2],
               [1,4],
               [1,4,2,3],
               [1,4,2],
               [1,2,3]]  # 装入数据 二维列表
    F, sup_data = Apriori(dataset, min_support=2)  # 最小支持度设置为2

    print("具有关联的菜品是{}".format(F))  # 带变量的字符串输出,必须为字典符号表示
    print('------------------')
    print("对应的支持度为{}".format(sup_data))
  1. 运行结果

运行结果:

具有关联的菜品是[[[1], [2], [3],[4], [5]], [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [4, 5]], [[1, 2, 3], [1, 2,4]]]

------------------

对应的支持度为{(1,): 7, (2,): 7,(3,): 3, (4,): 8, (5,): 2, (1, 2): 5, (1, 3): 3, (1, 4): 5, (2, 3): 3, (2, 4):5, (4, 5): 2, (1, 2, 3): 3, (1, 2, 4): 3}

五、实验小结

1、Apriori算法的基本思路是采用层次搜索的迭代方法,由候选(k-1)-项集来寻找候选k-项集,并逐一判断产生的候选k-项集是否是频繁的。

  设C k 是长度为k的候选项集的集合,Lk 是长度为k的频繁项集的集合。为了简单,设最小支持度阈值min_sup为最小元组数,即采用最小支持度计数。

通过扫描D得到1-频繁项集L1;

for(k=2;Lk-1!=Ф;k++)

{ Ck=由Lk-1通过连接运算产生的候选k-项集;

for (事务数据库D中的事务t)

{ 求Ck中包含在t中的所有候选k-项集的计数;

Lk={c | c∈Ckand c.sup_count≥min_sup};

//求Ck中满足min_sup的候选k-项集

}

}

returnL=∪kLk;

2、支持度(support):support(A=>B)= P(A∪B),表示A和B同时出现的概率。支持度就是几个关联的数据在数据集中出现的次数占总数据集的比重

3、Apriori性质

Apriori定律1:如果某商品组合小于最小支持度,则就将它舍去,它的超集必然不是频繁项集。

Apriori定律2:如果一个集合是频繁项集,即这个商品组合支持度大于最小支持度,则它的所有子集都是频繁项集。

4、Apriori算法的频繁项集产生的部分有两个重要的特点:(1)逐层算法,从频繁1-项集到最长的项集,每次遍历项集格中的一层。(2)它使用产生-测试(generate-and-test)策略来发现频繁项集,每次迭代后的候选项集都由上一次迭代发现的频繁项集产生。算法总迭代次数为kmax+1,其中kmax为频繁项集最大长度。

5、置信度不像支持度那样具有任何单调性。但是具有以下定理

定理:如果规则X→Y−X不满足置信度阈值,则形如X′→Y−X′的规则也一定不满足置信度阈值,其中X'是X的子集。

6、Aprori算法利可以很好的找出关联关系,但是每一次求候选集都需要扫描一次所有数据记录,那么在面临千万级别的数据记录就显得有点无力了。

你可能感兴趣的:(数据挖掘实验,python,big,data)