关联分析

概述:一种在大规模数据集中寻找有趣关系的任务。

这种关系形式:频繁项集或者关联规则

频繁项集:经常出现在一块的物品集合。
关联规则:暗示物品之间可能存在很强的关系。

对频繁的度量: 支持度和可信度

支持度:数据集中包含该项集的记录所占的比例

可信度或者置信度: 针对诸如:{尿布}->{葡萄酒}的关联规则来定义,这条规则的可信度被定义为:

“支持度({尿布, 葡萄酒})/支持度({尿布})”

支持度和可信度是用来量化关联分析是否成功的方法

经典算法:Apriori

Apriori

原理:如果某个项集是频繁的,那么它的所有子集也是频繁的。反之,如果一个项集是非频繁集,那么它的所有超集也是非频繁的

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

量化的定义:最小支持度

思想:
1、给定最小支持度和数据集,首先会生成所有物品的项集列表。
2、扫描交集记录来查看哪些项集满足最小支持度要求,不满足的会被去掉;
3、对剩下的集合进行组合已生成包含两个元素的项集;
4、重新扫描去掉不满足最小支持度项集,直到所有项集被去掉。

思考:如何从频繁项集中挖掘出关联规则

前件->后件

量化的定义:可信度,一条规则的可信度定义为:一条规则P->H可信度定义为: support(P|H)/support(P)

要找到关联规则,首先从一个频繁项集开始。由于集合中元素不是重复的,但我们想知道基于这些元素

能否获得其他内容。某个元素或者某个元素集合可能会推导出另一个元素。从杂货店例子,如果有一个

频繁项集{豆奶, 莴苣},可能有一条关联规则,“豆奶->莴苣”,但是反过来“莴苣->豆奶”并不总是

成立。

实践样例:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def loadDataSet():
    return [[1, 3, 4],[2, 3, 5],[1, 2, 3, 5],[2, 5]]

def createC1(dataSet):
    C1= []
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
    C1.sort()
    return [frozenset(i) for i in C1]


def scanD(D, Ck, minSupport):
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if can not in ssCnt.keys():
                    ssCnt[can] = 1
                else:
                    ssCnt[can] += 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):  # creates Ck
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i + 1, lenLk):
            # 前k-2个项相同时, 将2个集合合并
            L1 = list(Lk[i])[:k-2]
            L2 = list(Lk[j])[:k-2]
            L1.sort()
            L2.sort()
            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 = [set(i) for i in dataSet]
    L1, supportData = scanD(D, C1, minSupport)
    L = [L1]
    k = 2
    while len(L[k-2]) > 0:
        Ck = aprioriGen(L[k-2], k)
        Lk, supK = scanD(D, Ck, minSupport)  # 扫描数据集, 从Ck得到Lk
        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:
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
            else:
                calcConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
    prunedH = []
    for conseq in H:
        conf = supportData[freqSet] / supportData[freqSet-conseq]
        if conf >= minConf:
            print(f'{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):
    m = len(H[0])
    if len(freqSet) > m + 1:  # 尝试进一步合并
        Hmp1 = aprioriGen(H, m + 1)  # 创建Hm+1条新候选规则
        Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
        if len(Hmp1) > 1:
            rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)

if __name__ == '__main__':
    # 小数据集测试
    dataSet = loadDataSet()
    L, suppData = apriori(dataSet, minSupport=0.5)
    rules = generateRules(L, suppData,minConf=0.5)
    print(rules)

示例:发现国会投票中的模式、搜索引擎中查询词