关联分析--Apriori算法

关联分析–Apriori算法

关联分析是一种在大规模数据集中寻找有趣关系的任务。这些关系有两种形式:频繁项集或关联规则

  • 频繁项集是指经常出现在一起的物品集合。

  • 关联规则暗示两个物品之间可能存在很强的关系。 如 “{尿布} —> {啤酒}”这条关联规则,意味着如果有人买了尿布,就很可能也会买啤酒

使用频繁项集和关联规则,使商家可以更好的理解他们的顾客。大部分关联规则分析来自于零售业,也可以用于其他行业,比如网站流量分析以及医药行业。

概念

  • 项与项集:设 i t e m s e t = i t e m 1 , i t e m 2 , … , i t e m m itemset={item_1, item_2, …, item_m} itemset=item1,item2,,itemm是所有项的集合,其中, i t e m k ( k = 1 , 2 , … , m ) item_k(k=1,2,…,m) itemk(k=1,2,,m)成为项。项集(itemset)是由项的集合构成,包含k个项的项集称为k项集(k-itemset)

  • 关联规则:关联规则是形如A=>B的蕴涵式,其中A、B均为itemset的子集且均不为空集,而A交B为空。

  • 支持度(support):项集A支持度support(A)=数据集中包含该项集的记录数/总记录数

  • 可信度(或置信度):关联规则的可信度定义如下:

c o n f i d e n c e ( A ⇒ B ) = s u p p o r t ( A ∪ B ) s u p p o r t ( A ) confidence(A\Rightarrow B)=\frac{support(A\cup B)}{support(A)} confidence(AB)=support(A)support(AB)

​ 其中, s u p o o r t ( A ∪ B ) supoort(A\cup B) supoort(AB)表示集合A和集合B的并集的支持度。比如{尿布} —> {啤酒}这条关联规则的可信度定义为:支持度({尿布,啤酒})/支持度({尿布})。如果 {尿布,啤酒}的支持度为3/5,尿布的支持度为4/5,所以“尿 布 —>啤酒”的可信度为3/4=0.75。这意味着对于包含“尿布”的所有记录,我们的规则对其中75%的记录都适用

  • 频繁项集(frequent itemset):如果项集A的支持度满足事先定义好的最小支持度阈值,则A是频繁项集。

  • 强关联规则:满足最小支持度和最小可信度的关联规则,即待挖掘的关联规则。

定理

  1. 如果一个集合是频繁项集,则它的所有子集都是频繁项集。假设一个集合{A,B}是频繁项集,则它的子集{A}, {B} 都是频繁项集;

  2. 如果一个集合不是频繁项集,则它的所有超集都不是频繁项集。假设集合{A}不是频繁项集,则它的任何超集如{A,B},{A,B,C}必定也不是频繁项集。如下图所示
    关联分析--Apriori算法_第1张图片

关联分析

关联分析主要有两部分组成:

  • 使用Apriori算法发现频繁项集
  • 从频繁项集中挖掘关联规则

1. 使用Apriori算法发现频繁项集

Apriori算法的两个输人参数分别是最小支持度和数据集步骤如下

  1. 扫描数据集,生成所有单个项集的候选1项集C1;

  2. 扫描数据集D,计算候选k项集的支持度,剪枝去掉候选k项集中支持度低于最小支持度的集合得到频繁k项集。如果频繁k项集为空,则返回频繁k-1项集的集合作为算法结果,算法结束。否则,基于频繁k项集,连接生成候选k+1项集 ;

  3. 利用步骤2,迭代得到k=k+1项集结果;

可以从挖掘频繁项集的样例图解中直观理解过程
关联分析--Apriori算法_第2张图片

2. 从频繁集中挖掘关联规则

一旦找出了频繁项集,就可以直接由它们产生强关联规则。产生步骤如下:

  • 对于每个频繁项集freqset,产生freqset的所有非空子集(这些非空子集一定是频繁项集);
  • 对于freqset的每个非空子集s,如果 s u p p o r t ( f r e q s e t ) s u p p o r t ( f r e q s e t − s ) ≥ m i n c o n f \frac{support(freqset)}{support(freqset-s)}\geq minconf support(freqsets)support(freqset)minconf,则输出 ( f r e q s e t − s ) ⇒ s (freqset-s)\Rightarrow s (freqsets)s,其中minconf是最小可信度阈值。

如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求,例如下图的解释:
关联分析--Apriori算法_第3张图片

python按原理实现

完整python脚本如下,可直接运行

def loadDataSet():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

# 发现频繁项集
def createC1(dataSet):
    """
    创建候选项集C1
    :param dataSet:数据集(未集合化)
    :return:返回候选项集C1
    """
    C1 = []
    for transaction in dataSet:  # 每条清单
        for item in transaction:  # 清单中购买的每个物品
            if [item] not in C1:
                C1.append([item])
    C1.sort()
    return list(map(frozenset, C1))  # 对C1中的每个项构建一个不变子集


def scanD(D, Ck, minSupport):
    """
    扫描数据D,从 Ck 到 Lk,丢掉不满足最小支持度要求的项目
    :param D: 数据集(已经集合化)
    :param Ck: Ck
    :param minSupport: 最小支持度
    :return: 满足支持度的项集,以及该项集对应的支持度
    """
    ssCnt = {}
    for tid in D:
        for c in Ck:
            if c.issubset(tid):  # 如果集合c在该条清单中出现
                # 增加字典ssCnt中对应的计数值
                if c not in ssCnt:
                    ssCnt[c] = 1
                else:
                    ssCnt[c] += 1
    numItems = float(len(D))
    retList = []
    supportData = {}  # 所有候选项集的支持度
    for key in ssCnt:
        support = ssCnt[key] / numItems  # 计算各项的支持度
        if support >= minSupport:
            retList.insert(0, key)  # 将满足支持度的项插入到剩余项列表中
        supportData[key] = support
    return retList, supportData


def aprioriGen(Lk, k):
    """
    创建由k+1项组成的候选项集C(k+1),由 频繁项集Lk 到 C(k+1)
    """
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i + 1, lenLk):
            # 前k-2个项相同时,将两个集合合并
            # 比如L2:{0,1},{0,2},k-2就是0,即如果第一个元素相同,则进行合并
            L1 = list(Lk[i])[:k - 2]
            L2 = list(Lk[j])[:k - 2]
            if L1 == L2:
                retList.append(Lk[i] | Lk[j])
    return retList


def apriori(dataSet, minSupport=0.5):
    """
    获取所有满足条件的频繁项集的列表,和所有候选项集的支持度信息
    :param dataSet: 数据集(未集合化)
    :param minSupport:最小支持度
    :return:
    """
    C1 = createC1(dataSet)
    D = list(map(set, dataSet)) # 将dataSet集合化,以满足scanD的格式要求
    L1, supportData = scanD(D, C1, minSupport)
    L = [L1]
    k = 2
    while len(L[k - 2]) > 0:
        Ck = aprioriGen(L[k - 2], k)  # 创建Ck
        # 扫描数据,从 Ck 到 Lk,丢掉不满足最小支持度要求的项
        Lk, supK = scanD(D, Ck, minSupport)
        supportData.update(supK) # 将新的项集的支持度数据加入原来的总支持度字典中
        L.append(Lk)
        k += 1
    return L, supportData

# 从频繁项集中挖掘关联规则
def generateRules(L, supportData, minConf=0.7):
    """
    根据频繁项集和最小可信度生成规则集合
    :param L:频繁项集列表
    :param supportData:存储着所有项集(不仅仅是频繁项集)的支持度,是字典类型
    :param minConf:最小可信度阈值
    :return:
    """
    bigRuleList = []
    for i in range(1, len(L)):  # 只获取有两个或更多元素的集合
        for freqSet in L[i]:
            H1 = [frozenset([item]) for item in freqSet]  # 创建只包含单个元素集合的列表
            if i > 1:  # 如果频繁项集中的元素个数大于2,需要进一步合并
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
            else:  # 如果频繁项集中只有两个元素,则用calConf()
                calConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList


def calConf(freqSet, H, supportData, brl, minConf=0.7):
    """
    规则生成与评估,计算规则的可信度以及找到满足最小可信度要求的规则
    :param freqSet:频繁项集
    :param H:频繁项集中所有的元素
    :param supportData:频繁项集中所有元素的支持度,是字典类型
    :param brl:满足可信度条件的关联规则列表
    :param minConf:最小可信度阈值
    :return:
    """
    prunedH = []
    for conseq in H:
        conf = supportData[freqSet] / supportData[freqSet - conseq]
        if conf >= minConf:
            print(freqSet - conseq, "--->", conseq, 'conf:', conf)
            brl.append((freqSet - conseq, conseq, conf))
            prunedH.append(conseq)
    return prunedH


def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
    """
    从最初的项集中生成更多的关联规则,对频繁项集中元素超过2的项集进行合并
    :param freqSet:频繁项集
    :param H: 频繁项集中的所有元素,即出现在规则右部的元素列表
    :param supportData: 频繁项集中所有元素的支持度,是字典类型
    :param brl: 满足可信度条件的关联规则列表
    :param minConf: 最小可信度阈值
    :return:
    """
    m = len(H[0])  # H中频繁项集的大小
    # 查看频繁项集是否大到移除大小为 m 的子集,尝试进一步合并
    if len(freqSet) > (m + 1):
        Hmpl = aprioriGen(H, m + 1)  # 创建Hm+1条新候选规则
        Hmpl = calConf(freqSet, Hmpl, supportData, brl, minConf)
        # # 如果不止一条规则满足要求,则需要进一步递归合并,组合这些规则
        if len(Hmpl) > 1:
            rulesFromConseq(freqSet, Hmpl, supportData, brl, minConf)

运行结果如下:
关联分析--Apriori算法_第4张图片

算法优缺点

  • 优点:易编码

  • 缺点:在大数据集上可能较慢

相关链接

Apriori原理

机器学习实战-Apriori算法

你可能感兴趣的:(机器学习)