Apriori算法,python实现

首先看一下数据集结构,用excel建立一个数据集。

一行代表一个事务。假如有五个购买清单,一行代表一个单子。

代码如下:

import numpy as np
import pandas as pd

# 测试数据集,用于debug
def loadDataSet():
    df = pd.read_excel('D:\\Document_Exercitation\\关联规则apriori-python\\数据.xls',keep_default_na=False)
    retail = []
    for index, row in df.iterrows():
        data = row.tolist()
        data = [x for x in data if x != '']
        retail.append(data)
    #    retail = pd.DataFrame(data)
    print(retail)
    return retail

def creatC1(data):
    """
    找到1项候选集C1
    :param data: 数据集
    :return: 1项候选集C1
    """
    C1 = []
    for row in dataSet:
        for item in row:
            if [item] not in C1:
                C1.append([item])
    # 中文字符串升序排序
    C1.sort()
    # frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
    return list(map(frozenset, C1))


def calSupport(D, C, minSupport):
    """
    计算1项候选集的支持度,剔除小于最小支持度的项集,
    :param D: 数据集
    :param C1: 候选集
    :param minSupport: 最小支持度
    :return: 返回1项频繁集及其支持度
    """
    dict_sup = {}  # 中间储存变量,用于计数
    # 迭代每一条数据,对项集中的每一项进行计数
    for i in D:
        for j in C:
            # 集合j是否是集合i的子集,如果是返回True,否则返回False
            if j.issubset(i):
                # 再判断之前有没有统计过,没有统计过的话为1
                if j not in dict_sup:
                    dict_sup[j] = 1
                else:
                    dict_sup[j] += 1
    # 事务总数
    sumCount = float(len(D))
    # 计算支持度,支持度 = 项集的计数/事务总数
    supportData = {}  # 用于存储频繁集的支持度
    relist = []  # 用于存储频繁集
    for i in dict_sup:
        temp_sup = dict_sup[i] / sumCount
        # 将剔除后的频繁项集及其对应支持度保存起来
        if temp_sup > minSupport:
            relist.append(i)
            supportData[i] = temp_sup
    # 返回1项频繁项集及其对应支持度
    return relist, supportData


def aprioriGen(Lk, k):
    """
    改良了剪枝步,原来的Ck是由L1与L(k-1)来连接产生的,这里采用了新的连接方式
    使用剪枝算法,减少了候选集空间,找到k项候选集
    :param Lk: k-1项频繁集
    :param k: 第k项
    :return: 第k项候选集
    """
    reList = []  # 用来存储第k项候选集
    lenLk = len(Lk)  # 第k-1项频繁集的长度
    # 两两组合遍历
    for i in range(lenLk):
        for j in range(i + 1, lenLk):
            L1 = list(Lk[i])[:k - 2]
            L2 = list(Lk[j])[:k - 2]
            L1.sort()
            L2.sort()
            # 前k-1项相等,则可相乘,这样可以防止重复项出现
            if L1 == L2:
                a = Lk[i] | Lk[j]  # a为frozenset集合
                # 进行剪枝
                a1 = list(a)  # a1为k项集中的一个元素
                b = []  # b为它的所有k-1项子集
                # 构造b:遍历取出每一个元素,转换为set,依次从a1中剔除该元素,并加入到b中
                for q in range(len(a1)):
                    t = [a1[q]]
                    tt = frozenset(set(a1) - set(t))
                    b.append(tt)

                # 当b都是频繁集时,则保留a1,否则,删除
                t = 0
                for w in b:
                    # 如果为True,说明是属于候选集,否则不属于候选集
                    if w in Lk:
                        t += 1
                # 如果它的子集都为频繁集,则a1是候选集
                if len(b) == t:
                    reList.append(b[0] | b[1])

    return reList


def scanD(D, Ck, minSupport):
    """
    计算候选k项集的支持度,剔除小于最小支持度的候选集,得到频繁k项集及其支持度
    :param D: 数据集
    :param Ck: 候选k项集
    :param minSupport: 最小支持度
    :return: 返回频繁k项集及其支持度
    """
    sscnt = {}  # 存储支持度
    for tid in D:  # 遍历数据集
        for can in Ck:  # 遍历候选项
            if can.issubset(tid):  # 判断数据集中是否含有候选集各项
                if can not in sscnt:
                    sscnt[can] = 1
                else:
                    sscnt[can] += 1

    # 计算支持度
    numItem = len(D)  # 事务总数
    reList = []  # 存储k项频繁集
    supportData = {}  # 存储频繁集对应支持度
    for key in sscnt:
        support = sscnt[key] / numItem
        if support > minSupport:
            reList.insert(0, key)  # 满足条件的加入Lk中
            supportData[key] = support
    return reList, supportData


def apriori(dataSet, minSupport=0.2):
    """
    apriori关联规则算法
    :param data: 数据集
    :param minSupport: 最小支持度
    :return: 返回频繁集及对应的支持度
    """
    # 首先,找到1项候选集
    C1 = creatC1(dataSet)
    # 使用list()转化为列表,用于支持度计算
    D = list(map(set, dataSet))
    # 计算1项候选集的支持度,剔除小于最小支持度的项集,返回1项频繁集及其支持度
    L1, supportData = calSupport(D, C1, minSupport)
    L = [L1]  # 加列表框,使得1项频繁集称为一个单独的元素

    k = 2  # k项
    # 跳出循环的条件是没有候选集
    while len(L[k - 2]) > 0:
        # 产生k项候选集Ck
        Ck = aprioriGen(L[k - 2], k)
        # 计算候选k项集的支持度,剔除小于最小支持度的候选集,得到频繁k项集及其支持度
        Lk, supK = scanD(D, Ck, minSupport)
        # 将supK中的键值对添加到supportData
        supportData.update(supK)
        # 将第k项的频繁集添加到L中
        L.append(Lk)  # L的最后一个值为空值
        k += 1
    del L[-1]
    # 返回频繁集及其对应的支持度;L为频繁项集,是一个列表,1,2,3项集分别为一个元素
    return L, supportData


def getSubset(fromList, totalList):
    """
    生成集合的所有子集
    :param fromList:
    :param totalList:
    """
    for i in range(len(fromList)):
        t = [fromList[i]]
        tt = frozenset(set(fromList) - set(t))  # k-1项子集

        if tt not in totalList:
            totalList.append(tt)
            tt = list(tt)
            if len(tt) > 1:
                getSubset(tt, totalList)  # 所有非1项子集


def calcConf(freqSet, H, supportData, ruleList, minConf):
    """
    计算置信度,并剔除小于最小置信度的数据,这里利用了提升度概念
    :param freqSet: k项频繁集
    :param H: k项频繁集对应的所有子集
    :param supportData: 支持度
    :param RuleList: 强关联规则
    :param minConf: 最小置信度
    """
    # 遍历freqSet中的所有子集并计算置信度
    for conseq in H:
        conf = supportData[freqSet] / supportData[freqSet - conseq]  # 相当于把事务总数抵消了

        # 提升度lift计算lift=p(a&b)/p(a)*p(b)
        lift = supportData[freqSet] / (supportData[conseq] * supportData[freqSet - conseq])
        if conf >= minConf and lift > 1:
            print(freqSet - conseq, '-->', conseq, '支持度', round(supportData[freqSet], 6), '置信度:', round(conf, 6),
                  'lift值为:', round(lift, 6))
            ruleList.append((freqSet - conseq, conseq, conf))


def get_rule(L, supportData, minConf=0.7):
    """
    生成强关联规则:频繁项集中满足最小置信度阈值,就会生成强关联规则
    :param L: 频繁集
    :param supportData: 支持度
    :param minConf: 最小置信度
    :return: 返回强关联规则
    """
    bigRuleList = []  # 存储强关联规则
    # 从2项频繁集开始计算置信度
    for i in range(1, len(L)):
        for freqSet in L[i]:
            H1 = list(freqSet)
            all_subset = []  # 存储H1的所有子集
            # 生成所有子集
            getSubset(H1, all_subset)
            # print(all_subset)
            # 计算置信度,并剔除小于最小置信度的数据
            calcConf(freqSet, all_subset, supportData, bigRuleList, minConf)
    return bigRuleList


if __name__ == '__main__':
    dataSet = loadDataSet()
    # 返回频繁集及其对应的支持度
    L, supportData = apriori(dataSet, minSupport=0.02)
    # 生成强关联规则
    rule = get_rule(L, supportData, minConf=0.35)

加载文件 

    df = pd.read_excel('D:\\Document_Exercitation\\关联规则apriori-python\\数据.xls',keep_default_na=False)

这个函数用于从频繁项集中生成强关联规则。参数 minConf=0.35 指定了最小置信度阈值,表示生成的关联规则的置信度至少为 35%。

rule = get_rule(L, supportData, minConf=0.35) 

 这个函数实现了Apriori算法的主要流程,用于发现数据集中频繁项集。参数 minSupport=0.02 指定了最小支持度阈值,表示频繁项集在数据集中至少出现的比例为 2%。

L, supportData = apriori(dataSet, minSupport=0.02) 

测试结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值