Apriori算法手动实现

1. Apriori算法

关联规则挖掘是数据挖掘中最活跃的研究方法之一 。最早是由 Agrawal 等人提出的1993最初提出的动机是针对购物篮分析问题提出的,其目的是为了发现交易数据库中不同商品之间的联系规则。这些规则刻画了顾客购买行为模式,可以用来指导商家科学地安排进货,库存以及货架设计等。之后诸多的研究人员对关联规则的挖掘问题进行了大量的研究。他们的工作涉及到关联规则的挖掘理论的探索,原有的算法的改进和新算法的设计,并行关联规则挖掘Parallel Association Rule Mining,以及数量关联规则挖掘Quantitive Association Rule Mining 等问题。在提高挖掘规则算法的效率、适应性、可用性以及应用推广等方面,许多学者进行了不懈的努力。

该算法的基本思想是:首先找出所有的频集,这些项集出现的频繁性至少和预定义的最小支持度一样。然后由频集产生强关联规则,这些规则必须满足最小支持度和最小可信度。然后使用第1步找到的频集产生期望的规则,产生只包含集合的项的所有规则,其中每一条规则的右部只有一项,这里采用的是中规则的定义。一旦这些规则被生成,那么只有那些大于用户给定的最小可信度的规则才被留下来。为了生成所有频集,使用了递归的方法。

Apriori算法的伪代码如下:

在这里插入图片描述

2. 实验数据

常用到Groceries数据集,该数据集是某个杂货店一个月真实的交易记录,共有9835条消费记录,169个商品。

数据为传统的结构化数据,是一张二维表。每一行代表一个购物记录;每一列代表购物篮数据的一个特定项,其中第一列是购物篮中包含的项数,每条购物记录最多有32个项。数据可视化如下:

在这里插入图片描述

3. 实验思路

首先,我们先规定数据集dataset的格式为二维列表,第一维代表数据集中的样本(即购物记录),第二维代表样本的具体取值(即购物记录中的项)。

按照伪代码所示,我们编写代码,我们先定义几个函数:

3.1 数据预处理

我们从数据可视化记录中可以看出,原始的数据二维表中,存在许多的nan值,我们去除他们,并整个数据库转化为二维列表:

def LoadData():
    
    rawData = pd.read_csv('groceries - groceries.csv')
    dataset = []
    for data in rawData.values:
        data = set(data[1:])
        if np.nan in data:
            data.remove(np.nan)
        dataset.append(data)

    return dataset

3.2 产生频繁1项集

给定数据集和支持度,我们通过对购物记录中每一个特定的项计数,大于支持度的项集我们直接加入频繁项集中:

注意:频繁项集的格被设置为字典,其中键为频繁项集(格式为元组),值为对应的支持度计数。这样就可以很方便的记录所有频繁项集的支持度信息。

def GenerateFrequentItemset1(dataset, support):

    candidate = {}
    for data in dataset:
        for x in data:
            key = (x, )
            if key in candidate:
                candidate[key] += 1
            else:
                candidate[key] = 1

    frequentItemset1 = {key: value for key, value in candidate.items() if value >= support}

    return frequentItemset1

3.3 产生候选项集

给定频繁k项集集合,我们通过合并两两频繁k项集产生候选频繁k+1项集。

注意:这里我们假定项集的排列是有序的,我们只合并两个前k-1项相同的K项集。

def GenerateCandidateItemset(candidate):

    candidateNext = {}
    candidateKey = sorted(candidate)
    length = len(candidateKey)

    for i in range(length):
        front = candidateKey[i][:-1]
        for j in range(i+1, length):
            rear = candidateKey[j][:-1]
            if front == rear:
                candidateNext[candidateKey[i] + (candidateKey[j][-1], )] = 0
            else:
                break

    return candidateNext

3.4 候选项集剪枝

给定候选项集,我们通过扫描数据库,对其进行计数,之后根据先验原理对不满足小于支持度计数的候选项集进行剪枝,代码实现如下:

def PruneItemset(candidate, support, dataset):

    for data in dataset:
        for (i, key) in enumerate(candidate.keys()):
            if set(key).issubset(data):
                candidate[key] += 1

    prunedCandidate = {key: value for (key, value) in candidate.items() if value >= support}
    
    return prunedCandidate

3.5 Apriori频繁项集产生算法

给定数据集,支持度阈值,产生k项集。为了方便,我们将产生k项集过程中产生的所有频繁项集的记录保存到supportRecord中。具体代码如下:

def aprioriFrequentItemset(dataset, k, support):

    supportRecord = []
    frequentItemset1 = GenerateFrequentItemset1(dataset, support)
    frequentItemset = frequentItemset1
    supportRecord.append(frequentItemset)

    for i in range(k-1):
        candidateNext = GenerateCandidateItemset(frequentItemset)
        frequentItemset = PruneItemset(candidateNext, support, dataset)

        if len(frequentItemset.keys()) == 0:
            print('Not exist frequent itemset: {} with support = {}'.format(i+2, support))
            break

        supportRecord.append(frequentItemset)
    
    return frequentItemset, supportRecord

3.6 产生1后件规则

给定k频繁项集,我们可以从中提取出后件是1的规则,代码如下:

def GenerateRule1(frequentItemset):

    candidateRule1 = {}

    for key in frequentItemset.keys():
        front = (key[:-1], )
        rear = ((key[-1], ), )
        candidateRule1[(front + ('->', ) + rear)] = 0
    
    return candidateRule1

3.7 规则产生

给定m后件规则,我们从中提取出m+1后件的规则:

def GenerateRule(candidate):

    candidateNext = {}

    for key in list(candidate.keys()):
        front = (key[0][:-1], )
        rear = ((key[0][-1], ) + key[-1], )
        candidateNext[(front + ('->',) + rear)] = 0

    return candidateNext

3.8 规则剪枝

给定m后件规则,我们通过对其置信度计数进行剪枝,代码如下:

def PruneRule(candidate, confidence, record):

    prunedCandidate = {}

    for key in candidate.keys():
        front = key[0]
        rear = key[2]
        item = front + rear
        candidate[key] = record[len(item)-1][item] / record[len(front)-1][front]

    prunedCandidate = {key: value for (key, value) in candidate.items() if value >= confidence}

    return prunedCandidate

3.9 Apriori规则产生算法

与Apriori频繁项集产生算法类似的,给定频繁k项集,置信度,支持度计数,我们从中提取m后件规则并将再次过程中产生的规则保存在confidenceRecord中。

def aprioriRule(frequentItemset, m, confidence, supportRecord):

    confidenceRecord = []

    rule1 = GenerateRule1(frequentItemset)
    rule = PruneRule(rule1, confidence, record)
    confidenceRecord.append(rule)

    for i in range(m-1):
        candidateNext = GenerateRule(rule)
        rule = PruneRule(candidateNext, confidence, record)

        if len(rule.keys()) == 0:
            print('Not exist rule: {} with confidence = {}'.format(i+2, confidence))
            break

        confidenceRecord.append(rule)
    
    return rule, confidenceRecord

4. 实验结果

我们加载数据集,设置支持度阈值为200,产生频繁2项集。运行如下代码:

support = 200
k = 2
dataset = LoadData()
frequentItemset, supportRecord = aprioriFrequentItemset(dataset, k, support)

可以看到支持度大于200的频繁项集结果如下:

{('beef', 'whole milk'): 209,
 ('bottled beer', 'whole milk'): 201,
 ('bottled water', 'other vegetables'): 244,
 ('bottled water', 'rolls/buns'): 238,
 ('bottled water', 'soda'): 285,
 ('bottled water', 'whole milk'): 338,
 ('bottled water', 'yogurt'): 226,
 ('brown bread', 'whole milk'): 248,
 ('butter', 'whole milk'): 271,
 ('citrus fruit', 'other vegetables'): 284,
 ('citrus fruit', 'whole milk'): 300,
 ('citrus fruit', 'yogurt'): 213,
 ('curd', 'whole milk'): 257,
 ('domestic eggs', 'other vegetables'): 219,
 ('domestic eggs', 'whole milk'): 295,
 ('frankfurter', 'whole milk'): 202,
 ('frozen vegetables', 'whole milk'): 201,
 ('fruit/vegetable juice', 'other vegetables'): 207,
 ('fruit/vegetable juice', 'whole milk'): 262,
 ('margarine', 'whole milk'): 238,
 ('newspapers', 'whole milk'): 269,
 ('other vegetables', 'pastry'): 222,
 ('other vegetables', 'pip fruit'): 257,
 ('other vegetables', 'pork'): 213,
 ('other vegetables', 'rolls/buns'): 419,
 ('other vegetables', 'root vegetables'): 466,
 ('other vegetables', 'sausage'): 265,
 ('other vegetables', 'shopping bags'): 228,
 ('other vegetables', 'soda'): 322,
 ('other vegetables', 'tropical fruit'): 353,
 ('other vegetables', 'whipped/sour cream'): 284,
 ('other vegetables', 'whole milk'): 736,
 ('other vegetables', 'yogurt'): 427,
 ('pastry', 'rolls/buns'): 206,
 ('pastry', 'soda'): 207,
 ('pastry', 'whole milk'): 327,
 ('pip fruit', 'tropical fruit'): 201,
 ('pip fruit', 'whole milk'): 296,
 ('pork', 'whole milk'): 218,
 ('rolls/buns', 'root vegetables'): 239,
 ('rolls/buns', 'sausage'): 301,
 ('rolls/buns', 'soda'): 377,
 ('rolls/buns', 'tropical fruit'): 242,
 ('rolls/buns', 'whole milk'): 557,
 ('rolls/buns', 'yogurt'): 338,
 ('root vegetables', 'tropical fruit'): 207,
 ('root vegetables', 'whole milk'): 481,
 ('root vegetables', 'yogurt'): 254,
 ('sausage', 'soda'): 239,
 ('sausage', 'whole milk'): 294,
 ('shopping bags', 'soda'): 242,
 ('shopping bags', 'whole milk'): 241,
 ('soda', 'tropical fruit'): 205,
 ('soda', 'whole milk'): 394,
 ('soda', 'yogurt'): 269,
 ('tropical fruit', 'whole milk'): 416,
 ('tropical fruit', 'yogurt'): 288,
 ('whipped/sour cream', 'whole milk'): 317,
 ('whipped/sour cream', 'yogurt'): 204,
 ('whole milk', 'yogurt'): 551}

紧接着,我们设置置信度阈值为0.4,从中提取1后件规则:

confidence = 0.4
m = 1
rule, confidenceRecord = aprioriRule(frequentItemset, m, confidence, supportRecord)

我们得到如下1后件规则:

{(('beef',), '->', ('whole milk',)): 0.4050387596899225,
 (('butter',), '->', ('whole milk',)): 0.4972477064220184,
 (('curd',), '->', ('whole milk',)): 0.4904580152671756,
 (('domestic eggs',), '->', ('whole milk',)): 0.47275641025641024,
 (('frozen vegetables',), '->', ('whole milk',)): 0.4249471458773784,
 (('margarine',), '->', ('whole milk',)): 0.4131944444444444,
 (('root vegetables',), '->', ('whole milk',)): 0.44869402985074625,
 (('tropical fruit',), '->', ('whole milk',)): 0.40310077519379844,
 (('whipped/sour cream',), '->', ('whole milk',)): 0.44964539007092197}

我们观察可以发现一些有趣的结论:例如,消费者买了牛肉、黄油、豆腐、鸡蛋、蔬菜,有较大概率会买全脂牛奶。

同样的,我们设置支持度阈值100,置信度阈值为0.2,从中提取2后件规则:

support = 100
confidence = 0.2
k = 3
m = 2
dataset = LoadData()
frequentItemset, supportRecord = aprioriFrequentItemset(dataset, k, support)
rule, confidenceRecord = aprioriRule(frequentItemset, m, confidence, supportRecord)

我们得到的规则如下:

{(('butter',), '->', ('other vegetables', 'whole milk')): 0.20733944954128442}

消费者买了黄油,会有一定的概率买其他蔬菜和全脂牛奶。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值