关联分析-Apriori

news2024/11/16 1:15:39

关联分析-Apriori

1. 定义

关联分析就是从大规模数据中,发现对象之间隐含关系与规律的过程,也称为关联规则学习。

2. 相关概念

2.1 事务、项与项集

订单号购买商品
0001可乐、薯片
0002口香糖、可乐
0003可乐、口香糖、薯片

以上面的订单为例:

  • 事务:每条交易记录可称为一个事务。上面的订单中包含3个事务。
  • 项:指我们分析数据中的对象(物品)。上面3条交易记录中共包含3个项(可乐、薯片、口香糖)。
  • 项集:指由若干项构成的集合,k 个项组成的项集,叫 k 项集。

2.2 支持度

某项集在事务中出现的频率。即项集在事务中出现的次数除以事务总数。
s u p p o r t ( A ) = c o u n t ( A ) c o u n t ( d a t a s e t ) = P ( A ) support(A)=\frac{count(A)}{count(dataset)}=P(A) support(A)=count(dataset)count(A)=P(A)
支持度体现的就是某项集的出现频率,只有某项集的支持度达到一定程度,才有研究该项集的必要。

2.3 置信度

关联规则 ( A → B ) (A\rightarrow B) (AB)中, A A A B B B同时出现的次数,除以 A A A出现的次数。表示 A A A发生的前提下, B B B发生的概率。
c o n f i d e n c e ( A → B ) = c o u n t ( A B ) c o u n t ( A ) = c o u n t ( A B ) / c o u n t ( d a t a s e t ) c o u n t ( A ) / c o u n t ( d a t a s e t ) = P ( A B ) P ( A ) = P ( B ∣ A ) confidence(A\rightarrow B)=\frac{count(AB)}{count(A)}\\=\frac{count(AB)/count(dataset)}{count(A)/count(dataset)}\\ = \frac{P(AB)}{P(A)} \\ =P(B|A) confidence(AB)=count(A)count(AB)=count(A)/count(dataset)count(AB)/count(dataset)=P(A)P(AB)=P(BA)
置信度体现的时关联规则的可靠程度。若关联规则 ( A → B ) (A\rightarrow B) (AB)的置信度较高,则说明当 A A A发生时, B B B也有很大概率发生。

2.4 提升度

关联规则 ( A → B ) (A\rightarrow B) (AB)中,提升度是指 ( A → B ) (A\rightarrow B) (AB)的置信度除以 B B B的支持度
l i f t ( A → B ) = c o n f i d e n c e ( A → B ) s u p p o r t ( B ) = P ( A B ) P ( A ) P ( B ) lift(A\rightarrow B)=\frac{confidence(A\rightarrow B)}{support(B)}=\frac{P(AB)}{P(A)P(B)} lift(AB)=support(B)confidence(AB)=P(A)P(B)P(AB)
提升度体现的是组合(应用关联规则)相对不组合(不应用关联规则)的比值。

  • 若提升度大于1,则说明该关联规则是有价值的,起促进作用;

  • 若提升度等于1,表示管理那规则不产生影响;

  • 若提升度小于1,说明应用该关联规则起到了负面影响。

因此应尽可能让关联规则的提升度大于1,提升度越大,则应用该关联规则的效果越好。

2.5 频繁项集

通常,我们仅对频繁出现的项集进行研究。因此,我们会设计一个支持度阈值,若一个项集的支持度大于等于该阈值,则该项集就称为频繁项集。若频繁项集中含有k个元素,则称其为频繁k项集。

3. 关联分析过程

关联分析可分为如下两个过程:

  1. 从数据集中寻找频繁项集
  2. 从频繁项集中生成关联规则

3.1 寻找频繁项集

首先,我们需要能够找到所有的频繁项集,即经常出现在一起的对象集合。一般只要按如下步骤来进行即可 :

  1. 遍历对象之间所有可能的组合(包括单个对象的组合),每种组合构成一个项集
  2. 针对每一个项集A,计算A的支持度(A出现的次数除以记录总数)。
  3. 返回所有支持度大于指定阈值的项集。

上面的订单的频繁项集如下:

在这里插入图片描述

上面寻找频繁项集的方法,理论上是没有问题的,但却很难在实际应用中使用。如,在上图中,3个不同
的对象(项),可以构成8种组合。而对于含有 N N N个对象的数据集,总共可以构成 2 N − 1 2^N - 1 2N1种组合。当 N N N比较大时,计算量就会按指数级增长。

因此,为了降低计算量,我们使用Apriori算法进行优化。Apriori算法的原理如下:

  1. 如果一个项集是频繁项集,则其所有子集(非空)也是频繁项集
  2. 如果一个项集(非空)是非频繁项集,则其所有父集也是非频繁项集

Apriori算法会从 k = 1 k=1 k=1开始,使用两个 k k k项集进行组合,从而产生 k + 1 k+1 k+1项集。结合之前介绍的算法原理可知,频繁 k + 1 k+1 k+1项集是由两个 k k k项集组合而成的,而对于频繁 k + 1 k+1 k+1项集来说,其所有 k k k项集的子集必然都是频繁项集,这就意味着,频繁 k + 1 k+1 k+1项集只可能由两个频繁 k k k项集组合产生。因此,在组合的过程中,一旦发现某个 k k k项集不是频繁项集(支持度小于指定的阈值),就可以将其移除,而无需再参与后续生成 k + 1 k+1 k+1项集的组合。这样一来,就可以大大减少计算量。

在这里插入图片描述

例如在上图中,假设(薯片,口香糖)是非频繁项集,则根据Apriori算法,其所有父集也是非频繁项集,故(可乐,薯片,口香糖)也是非频繁项集。因此,我们就没有必要使用(薯片,口香糖)与其他2项集进行组合去生成3项集了,因为生成的3项集(可乐,薯片,口香糖)也是非频繁项集。

3.2 Apriori算法流程

Apriori算法是第一个关联规则挖掘算法,它利用逐层搜索的迭代方法找出数据库中项集的关系,以形成规则,其过程由连接(类矩阵运算)与剪枝(去掉那些没必要的中间结果)组成。该算法中项集的概念即为项的集合。包含k个项的集合为k项集。项集出现的频率是包含项集的事务数,称为项集的频率。如果某项集满足最小支持度,则称它为频繁项集。

Apriori算法流程如下:

  1. 扫描数据集,从数据集中生成候选 k k k项集 C k C_k Ck k k k从1开始)。

  2. 计算 C k C_k Ck中,每个项集的支持度,删除低于阈值的项集,构成频繁项集 L k L_k Lk

  3. 将频繁项集 L k L_k Lk中的元素进行组合,生成候选 k + 1 k+1 k+1项集 C k + 1 C_{k+1} Ck+1

  4. 重复步骤2、3,直到满足以下两个条件之一时,算法结束

    • 频繁项集无法组合生成更大的候选项集

    • 所有的候选项集支持度都低于指定的阈值(最小支持度),无法生成频繁项集

说明:这里的 C k C_k Ck是指所有的候选 k k k项集, L k L_k Lk是指所有的频繁 k k k项集。

4. 生成关联规则

当产生频繁项集后,生成关联规则会相对简单,我们只需要将每个频繁项集拆分成两个非空子集,然后就可以使用这两个子集构成关联规则。当
然,一个频繁项集拆分成两个非空子集可能有很多种方式,我们要考虑每一种不同的可能。例如,频繁项集 { 1 , 2 , 3 } \{1,2,3\} {1,2,3}可以生成如下6个关联规则:
{ 1 → 2 , 3 } \{1\rightarrow2,3\} {12,3}
{ 2 → 1 , 3 } \{2\rightarrow1,3\} {21,3}
{ 3 → 1 , 2 } \{3\rightarrow1,2\} {31,2}
{ 1 , 2 → 3 } \{1,2\rightarrow3\} {1,23}
{ 1 , 3 → 2 } \{1,3\rightarrow2\} {1,32}
{ 2 , 3 → 1 } \{2,3\rightarrow1\} {2,31}
然后,针对每个关联规则,分别计算其置信度,仅保留符合最小置信度的关联规则。

5. 代码实现

数据下载:

链接:https://pan.baidu.com/s/1OSHupRjmHmMv3F0rwRwnpQ?pwd=fhh6
提取码:fhh6

import pandas as pd
import itertools

# 加载数据集
def load_data(path):
    result = []
    with open(path) as f:
        for line in f:
            line = line.strip("\n")
            result.append(line.split(","))
    return result


# 生成候选1项集列表
# 接下来,扫描加载后的数据集,生成候选1项集列表。
# 因为候选1项集列表是从原始数据集中生成的,因此,
# 列表中的每个元表就是数据集中不重复的对象。
# 为了方便后面的操作,将每个对象放入frozenset中。
# 将每个对象放入frozenset而不是set中,
# 是为了将元素作为字典的key
def buildC1(dataset):
    item1 = set(itertools.chain(*dataset))
    return [frozenset([i]) for i in item1]



def ck_to_lk(dataset, ck, min_support):
    """根据候选k项集与对应的最小支持度,创建生成频繁k项集

    """
    # 定义项集-频数字典
    support = {}
    for row in dataset:
        for item in ck:
            # 判断项集是否在记录中出现
            if item.issubset(row):
                support[item] = support.get(item, 0) + 1
    total = len(dataset)
    return {k: v / total for k, v in support.items() if v / total >= min_support}

# 频繁k项集组合成候选k+1项集

# 当产生频繁K项集之后,需要对频繁k项集中的元素进行组合
# 如果组合后的项集数量为k +1,则保留此种组合,
# 否则,丢弃此种组合。
def lk_to_ck(lk_list):
    """根据参数指定的频繁k项集,组合生成候选k+1项集

    """

    # 保存所有组合之后的候选k+1项集
    ck = set()
    lk_size = len(lk_list)
    # 如果频繁k项集的数量不大于1,
    # 则不可能再通过组合生成候选k+1项
    # 直接返回空set即可
    if lk_size > 1:
        # 获取频繁k项集的k值
        k = len(lk_list[0])
        # 获取任意两个元素序号的索引组合
        for i, j in itertools.combinations(range(lk_size), 2):
            # 将对应位置的两个频繁k项集进行组合,生成一个新的项集
            t = lk_list[i] | lk_list[j]
            # 若组合后的项集时k+1项集,则为候选k+1项集,加入到set中
            if len(t) == k + 1:
                ck.add(t)
    return ck




# 生成所有频繁项集
def get_L_all(dataset, min_support):
    """根据最小支持度,从指定的数据集中,返回所有的频繁项集

    """
    c1 = buildC1(dataset)
    L1 = ck_to_lk(dataset, c1, min_support)
    # 定义字典,保存所有的频繁k项集
    L_all = L1
    Lk = L1
    # 当频繁项集字典中的元素数量大于1时,才有可能组合生成候选k+1项集
    while len(Lk) > 1:
        lk_key_list = list(Lk.keys())
        # 由频繁k项集生成候选k+1项集
        ck = lk_to_ck(lk_key_list)
        # 由候选k+1项集组合生成频繁k+1项集
        Lk = ck_to_lk(dataset, ck, min_support)
        # 若频繁k+1项集字典不为空,则将所有频繁k+1项集加入到L_all字典中
        if len(Lk) > 0:
            L_all.update(Lk)
        else:
            # 频繁k+1项集为空,退出循环
            break
    return L_all



# 生成关联规则
def rules_from_item(item):
    """从指定的频繁项集中生成关联规则

    """
    # 定义规则左侧的列表
    left = []
    for i in range(1, len(item)):
        left.extend(itertools.combinations(item, i))
    return [(frozenset(le), frozenset(item.difference(le))) for le in left]

"""
当生成包含所有频繁K项集的字典后,我们就可以遍历字典中的每一个频繁项集,进而计算该频繁项集的所有可能的关联规则,然后对每一个可能的关联规则,计算置信度,保留符合最小置信度的关联规则。
"""


def rules_from_L_all(L_all, min_confidence):
    """从所有频繁项集字典中生成关联规则列表

    """
    # 保存所有候选的关联规则
    rules = []
    for Lk in L_all:
        # 若频繁项集的元素个数为1,则无法生成关联规则,不予考虑
        if len(Lk) > 1:
            rules.extend(rules_from_item(Lk))
    result = []
    for left, right in rules:
        support = L_all[left | right]
        confidence = support / L_all[left]
        lift = confidence / L_all[right]
        if confidence >= min_confidence:
            result.append({"左侧": left, "右侧": right, "支持度": support, "置信度": confidence, "提升度": lift})
    return result

def apriori(dataset ,min_support, min_confidence):
    L_all = get_L_all(dataset,min_support)
    rules = rules_from_L_all(L_all, min_confidence)
    return rules

# 将对象的编号转换成名称
def change(item):
    li = list(item)
    for i in range(len(li)):
        li[i] = index_to_str[li[i]]
    return li

if __name__=="__main__":
    dataset = load_data("data.csv")
    # print(dataset)

    # 编码转换
    # 对原始数据进行转换,将字符串映射为索引

    items = set(itertools.chain(*dataset))
    str_to_index = {}
    index_to_str = {}
    for index, item in enumerate(items):
        str_to_index[item] = index
        index_to_str[index] = item
    # 输出结果#
    # print("字符串到编号:", list(str_to_index.items())[:5])
    # print("编号到字符串:", list(index_to_str.items())[:5])

    for i in range(len(dataset)):
        for j in range(len(dataset[i])):
            dataset[i][j] = str_to_index[dataset[i][j]]
    # print(dataset)
    
    rules = apriori(dataset, 0.05, 0.3)

    df = pd.DataFrame(rules)
    df = df.reindex(["左侧", "右侧", "支持度", "置信度", "提升度"], axis=1)
    df["左侧"] = df["左侧"].apply(change)
    df["右侧"] = df["右侧"].apply(change)
    print(df)

参考资料

  1. https://edu.csdn.net/learn/36761/565907?spm=3001.4143
  2. https://blog.csdn.net/weixin_53823523/article/details/119845775
  3. https://baike.baidu.com/item/APRIORI/2000746?fr=ge_ala

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/798322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一套流程6个步骤,教你如何正确采购询价

采购询价(RFQ)是一种竞争性投标文件,用于邀请供应商或承包商就标准化或重复生产的产品或服务提交报价。 询价通常用于大批量/低价值项目,买方必须提供技术规格和商业要求,该文件有时也称为招标书或投标邀请书。询价流…

客户问题解决平台-帮助与支持中心

在现代企业中,帮助与支持中心扮演着至关重要的角色。随着市场的竞争日趋激烈,客户对于产品和服务的期望也越来越高。因此,建立一个高效的客户问题解决平台是企业成功的关键之一。本文将探讨帮助与支持中心的作用,介绍其功能和优势…

Linux(二)--Linux基础命令

我们在前面学习的Linux命令,其实它们的本体就是一个个的二进制可执行程序。 和Windows系统中的.exe文件,是一个意思。 一.Linux的目录结构 Linux的目录结构是一个树形结构。 Windows系统可以拥有多个顶级目录,称之为盘符,如C盘&…

Journal of Information Security and Applications (JISA) 投稿经验分享

Journal of Information Security and Applications (JISA) 投稿经验分享 基本情况: 中科院三区 JCR Q2 2023影响因子:5.6 老牌信息安全类期刊 投稿经验: With editor 周期: 1-2个月,稍微有点慢 Under review 周期: 2…

Nautilus Chain 即将发行治理通证 NAUT ,生态发展进程加速

独特且优势明显的 Nautilus Chain 目前,行业内首个模块化底层 Nautilus Chain 已经上线主网,并且即将有超过 70 个应用原生部署在 Nautilus Chain 上。Nautilus Chain 本身是一个以 Layer3 为定位的区块链系统,其通过 Celestia 模块化底层来获…

C++初阶之一篇文章让你掌握string类(模拟实现)

string类模拟实现 1.为什么要模拟实现string2.string的模拟实现需要注意哪些问题3.经典的string类问题4.写时拷贝5.传统版写法的String类(参考)6.现代版写法的String类(参考)7.string类的模拟实现(讲解)7.1…

Vue基础-综合案例(基于vue2)

一、目标 能够知道如何使用vue-cli创建vue项目能够知道如何在项目中安装与配置element-ui能够知道element-ui中常见组件的用法能够知道如何使用axios中的拦截器能够知道如何配置proxy接口代理 二、目录 vue-cli组件库axios拦截器proxy跨域代理用户列表案例 vue-cli 1.什么…

浅谈密码学的由来

目录 1.什么是密码学 2.密码学的发展 3.密码学的应用 4.密码学未来的发展趋势 1.什么是密码学 密码学是关于安全通信的科学研究,它研究如何在敌对环境中保护通信的机密性、完整性和身份验证。密码学涉及使用各种算法和技术来加密和解密信息,以确保只有…

C++基础算法⑤——递推算法(昆虫繁殖 过河卒 Pell数列 上台阶 流感传染 移动路线)

递推掌握核心&#xff1a; 递推公式(规律)递推边界(初始化条件) 分析题目意思&#xff1a;如下图 递推式&#xff1a;a[n] a[n-1]a[n-2]; 递推边界&#xff1a;a[1]1 a[2]2 #include<iostream> using namespace std; long long a[100],x,y,z; int main(){ //昆虫繁衍…

c++类和对象(拷贝构造、运算符重载、初始化列表、静态成员、友元等)

一、拷贝构造 拷贝构造函数的特征&#xff1a; 1、拷贝构造函数是构造函数的一个重载形式&#xff1b; 2、拷贝构造函数的参数只有一个且必须是同类类型对象的引用&#xff0c;使用传值方式编译器直接报错&#xff0c;因为会引发无穷递归调用。 在c中自定义类型传值传参的时…

vue中的.env文件分析

问题说明 有米有小伙伴&#xff0c; 在看一个新鲜的项目的时候&#xff0c; 会发现在项目中会有类似于下方的文件。 那这些文件是干什么的呢&#xff1f; 它们在项目中会有什么作用呢&#xff1f; 如何调用这些文件的呢 问题解答 0&#xff0c;对于vue中模式与环境变量的说…

专注:如何提高专注力和注意力的简要指南

专注力和集中力可能很难掌控的很好。大多数人都想学习如何提高注意力和注意力。但真的做到了&#xff1f;我们生活在一个嘈杂的世界里&#xff0c;不断的分心会使注意力难以集中。 此指南包含有关如何获得并保持专注的研究。我们将分解提升您的思维并关注重要事物背后的理论依…

平衡二叉树介绍

一、树的概念 1.1 空树和非空树 空树&#xff1a;结点数为0的树 非空树&#xff1a;有且仅有一个根节点。其中&#xff0c;没有后继的结点叫叶子结点&#xff0c;有后继的结点叫做分支结点。 如下图所示&#xff1a; 1.2树的属性 除了根结点外任何一个结点都有且仅有一个前…

阿里Java开发手册~应用分层

1. 【推荐】图中默认上层依赖于下层&#xff0c;箭头关系表示可直接依赖&#xff0c;如&#xff1a;开放接口层可以依赖于 Web 层&#xff0c;也可以直接依赖于 Service 层&#xff0c;依此类推&#xff1a; 开放接口层 &#xff1a;可直接封装 Service 方法暴露成 RP…

600就能用上7000MHz的DDR5内存,这套32GB的光威天策真是快又稳

大家都知道&#xff0c;DDR5内存性能提升很大&#xff0c;而且Intel 13代平台和AMD Zen 4平台都已经兼容了&#xff0c;可以带来更稳定的性能表现&#xff0c;之前因为DDR5内存价格高昂&#xff0c;许多消费者望而却步&#xff0c;而随着今年DDR5内存售价的逐渐下降&#xff0c…

css3的filter图片滤镜使用

业务介绍 默认&#xff1a;第一个图标为选中状态&#xff0c;其他三个图标事未选中状态 样式&#xff1a;选中状态是深蓝&#xff0c;未选中状体是浅蓝 交互&#xff1a;鼠标放上去选中&#xff0c;其他未选中&#xff0c;鼠标离开时候保持当前选中状态 实现&#xff1a;目前…

Docker的数据管理和Dockerfile的指令

Docker的数据管理 一、Docker数据的概念1、数据卷2、数据卷容器 二、端口映射三、容器互联&#xff08;使用centos镜像&#xff09;四、Docker 镜像的创建1、基于现有镜像创建&#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改&#xff08;2&#xff09;然…

经营在线业务的首选客服工具--SS客服

随着网购正在快速取代传统零售业&#xff0c;各行各业的企业都在大力发展电子商务以取悦客户。但是&#xff0c;有这么多可用的电子商务平台&#xff0c;选择一款符合自己发展的平台确实不容易。电子商务平台不仅是企业在线销售产品和服务的地方&#xff0c;也是他们管理日常运…

Vue2基础三、计算属性侦听器

零、文章目录 Vue2基础三、计算属性&侦听器 1、计算属性computed &#xff08;1&#xff09;基础语法 概念&#xff1a; 基于现有的数据&#xff0c;计算出来的新属性。 依赖的数据变化&#xff0c;自动重新计算。计算属性会对计算出来的结果缓存&#xff0c;再次使用…

Linux三剑客与正则

目录 正则表达式 text测试文件 正则符号分类 基础正则符号 正则表达式的贪婪性 扩展正则符号 linux三剑客 三剑客特点及应用场景 grep sed sed命令执行过程 sed查找script sed删除script sed增加script 具体功能 具体script sed替换script 后向引用 awk aw…