【频繁模式挖掘】Apriori算法(附Python实现)

news2024/11/25 4:42:59

一、实验内容简介

该实验主要使用频繁模式关联规则进行数据挖掘,使用Apriori算法和Python语言来编写和设计程序,然后用不同规模的数据集来检验效果,最后分析和探讨实验结果,看其是否达到了理想的效果。

image-20240406095635642

二、算法说明

关联规则是形如 X→Y 的蕴涵表达式,其中 X 和 Y 是不相交的项集,即 X∩Y=∅。关联规则的强度可以用它的支持度(support)和置信度(confidence)来度量。计算公式如下:

支持度:support(A=>B) = P(A∪B),表示 A 和 B 同时出现的概率。

置信度:confidence(A=>B)=support(A∪B) / support(A),表示 A 和 B 同时出现的概率占 A 出现概率的比值。

强关联规则是指达到了最小支持度和最小置信度的关联规则。

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

三、算法分析与设计

了解完算法的基本原理后,现在开始真正实现该算法。首先需要读取最小支持度,读取数据集。这里的数据集可大可小,我用Python中的字典来表示数据集,既方便又不容易出错。然后是频繁模式的存储,这里使用列表,前面k个元素表示具体的事务,最后一个元素表示前面元素的组合在数据集中出现的错误。

运用面向对象的思想,把Apriori算法封装成一个类。首先写构造函数进行初始化:

def __init__(self, support: float, data: dict):
    """
        初始化
        :param support: 支持度
        :param data: 数据集
        """
    self.support = support
    self.data = data
    self.FirstList = []  # 第一轮扫描后的频繁模式
    self.FinalList = []  # 最后的频繁模式
    self.FinalList_noValue = []  # 最后的频繁模式(不包括频率)
    self.allList = []  # 所有的频繁模式

自定义几个列表(存放频繁模式)、初始化支持度和数据集。

接着进行第一轮扫描,把出现次数达到最小支持度要求的1项集先提取出来。具体方式就是通过遍历数据集一个一个找。然后建立一个字典,把每一项的名字作为关键字,再把这一项出现的次数作为值。

def findFirst(self):
    dict = {}
    for value in self.data.values():
    for i in value:
    if i in dict.keys():
    dict[i] += 1
    else:
    dict[i] = 1
    for key, value in dict.items():
    if value >= self.support * len(self.data):
    self.FirstList.append(key)
    # 进行后面的扫描
    self.findMore()

接着进行后续的扫描,后续的扫描的过程大体上相同,于是在findMore函数中就可以使用递归,简化代码。基本思路是将上一次遍历的k-1项集来合成k项集,这里使用集合的并运算,同时控制长度,符合要求后转换成列表进行排序(不排序的话内部会呈乱序排列,因为集合没有顺序),然后再转换成元组(元组才能通过哈希作为字典的关键字)返回。接着跟第一次扫描的思路大体相同,挨个遍历,获得频繁项集。不停地递归下去,直到下一个返回的列表为空,这时这一次获得的就是最大频繁项集。

def findMore(self, k=2):
    """
    进行第二次至第k次扫描
    """
    # 具体代码实现较长,详见附录

最后得到结果后当然要进行输出,这里也把输出结果简单地封装了一下。主要输出结果有最大频繁项集和支持度最高的频繁项集。

def __str__(self):
    # 输出运算符重载,也就是输出最终信息
    if self.allList:  # 验证是否为空
    self.allList.sort(key=lambda l: (l[-1], len(l)), reverse=True)
    print("所有的频繁模式按支持度从大到小为" + str(self.allList))
    print("极大频繁模式为" + str(self.FinalList))
    return '前k个频繁模式按支持度从大到小为' + str(self.allList[0:len(self.FinalList[-1]) - 1])
    return '无频繁模式!'

四、测试结果

在写完代码后,最重要的就是进行大量的测试,来分析其正确性与性能。

首先验证正确性。我首先使用了一个很简单的数据集来验证。

img

先给定0.5的支持度:

img

经过验证是正确的,再试试0.15的支持度:

img

再试试0.9的支持度,这个支持度很高,没有任何一个组合能够达到:

img

程序也成功输出了正确结果。

接下来就要扩大数据集的容量了,这样才能分析算法的性能。这里使用随机变量来模拟大量的数据:

img

在这里,arr和data2都可以修改,arr可以修改其中的元素来改变权重(如arr2),data2可以修改数量,这里统一使用0.5作为支持度。

首先用100000的数据来测试:

img

可以看到,一共花了1.7秒。

再使用arr2:

img

可以看到,牛奶的支持度显著上升。

然后把数据量变为1000000来试试:

img

一共花了15.58秒。

然后把数据量变为10000000来试试:

img

一共花了171.1秒,可以看出,它花费的时间与数据量规模大小成正比。

五、分析与探讨

测试完算法后,来分析它的性能,思考还有哪些能改进的地方。首先可以看到,因为Apriori算法每次迭代都要对全部数据进行一次扫描,这显然是比较低效的。同时,该算法使用的数据结构也是比较低级的线性表,跟树、并查集等其他数据结构比起来也显得比较低效。但是,该算法有助于我们理解频繁模式挖掘,同时它也启发了其他的高效算法,是我们学习频繁模式的很好的入门级算法。

因为该算法本身的原因,它的优化有瓶颈限制,最多进行一些语法上的优化和一些小技巧。如果要进行大幅度的性能改进,还要使用其他的高效算法,如FP-Tree算法等。

附录:源代码

"""
输入事务集,给定支持度
输出所有的频繁模式,并按支持度降序排列
输出极大频繁模式,并按支持度排序
输出支持度最大的前k个频繁模式
"""
import time
import itertools
import random


class Apriori:
    def __init__(self, support: float, data: dict):
        """
        初始化
        :param support: 支持度
        :param data: 数据集
        """
        self.support = support
        self.data = data
        self.FirstList = []  # 第一轮扫描后的频繁模式
        self.FinalList = []  # 最后的频繁模式
        self.FinalList_noValue = []  # 最后的频繁模式(不包括频率)
        self.allList = []  # 所有的频繁模式

    def findFirst(self):
        """
        第一次扫描
        """
        dict = {}
        for value in self.data.values():
            for i in value:
                if i in dict.keys():
                    dict[i] += 1
                else:
                    dict[i] = 1
        for key, value in dict.items():
            if value >= self.support * len(self.data):
                self.FirstList.append(key)
        # 进行后面的扫描
        self.findMore()

    def findMore(self, k=2):
        """
        进行第二次至第k次扫描
        """
        Dict = {}
        List_k = []
        List_k_noValue = []
        # 寻找最大频繁项集
        if k == 2:
            C = list(itertools.combinations(self.FirstList, k))
        else:
            C = self.Ck(k)
        for i in C:
            for value in self.data.values():
                if set(i).issubset(set(value)):
                    if i in Dict:
                        Dict[i] += 1
                    else:
                        Dict[i] = 1
        for key, value in Dict.items():
            if value >= self.support * len(self.data):
                list_temp = list(key)
                List_k_noValue.append(list_temp.copy())
                list_temp.append(value)
                List_k.append(list_temp)
        if List_k:
            List_k.sort(key=lambda l: l[-1], reverse=True)
            self.allList.extend(List_k)
            self.FinalList_noValue = List_k_noValue
            self.FinalList = List_k
            self.findMore(k + 1)

    def Ck(self, k):
        """
        根据k-1项的频繁项集列表生成k项的候选项集
        :return: ck项集
        """
        Ck_list = []
        for i in range(len(self.FinalList_noValue) - 1):
            for j in range(i + 1, len(self.FinalList_noValue) - 1):
                s = set(self.FinalList_noValue[i]) | set(self.FinalList_noValue[j])
                s = list(s)
                s.sort()
                if len(s) == k and tuple(s) not in Ck_list:
                    Ck_list.append(tuple(s))
        return Ck_list

    def __str__(self):
        # 输出运算符重载,也就是输出最终信息
        if self.allList:  # 验证是否为空
            self.allList.sort(key=lambda l: (l[-1], len(l)), reverse=True)
            print("所有的频繁模式按支持度从大到小为" + str(self.allList))
            print("极大频繁模式为" + str(self.FinalList))
            return '前k个频繁模式按支持度从大到小为' + str(self.allList[0:len(self.FinalList[-1]) - 1])
        return '无频繁模式!'


if __name__ == '__main__':
    try:
        support = float(input("请给出最小支持度:"))
        if support <= 0 or support >= 1:
            raise Exception("范围错误")
    except ValueError:
        print('输入类型错误')
    except Exception as e:
        print(e)
    else:
        data = {
            1: ['A', 'B', 'C'],
            2: ['A', 'C'],
            3: ['A', 'B', 'C', 'D'],
            4: ['B', 'C', 'E'],
            5: ['A', 'C', 'E'],
            6: ['A', 'B', 'C', 'F'],
            7: ['A', 'B', 'C']
        }
        arr = ['牛奶', '面包', '鸡蛋', '馒头', '包子', '饼干']
        arr2 = ['牛奶', '面包', '鸡蛋', '馒头', '包子', '饼干','牛奶','牛奶']
        data2 = {i: [random.choice(arr) for j in range(10)] for i in range(1000000)}
        start = time.time()
        A = Apriori(support, data2)
        A.findFirst()
        print(A)
        # 给出运行时间
        end = time.time()
        print("本次运行一共花了%.4f秒" % (end - start))
    finally:
        print("程序运行完毕!")

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

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

相关文章

2024年生成式人工智能的现状:进展、挑战与未来展望的深入分析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

wireshark抓包新手使用教程

Wireshark是非常流行的网络封包分析软件&#xff0c;可以截取各种网络数据包&#xff0c;并显示数据包详细信息。常用于开发测试过程各种问题定位。本文主要内容包括&#xff1a; 1、Wireshark软件下载和安装以及Wireshark主界面介绍。 2、WireShark简单抓包示例。通过该例子学…

【C++航海王:追寻罗杰的编程之路】探寻实用的调试技巧

目录 1 -> 什么是bug&#xff1f; 2 -> 调试是什么&#xff1f;有多重要&#xff1f; 2.1 -> 调试是什么&#xff1f; 2.2 -> 调试的基本步骤 2.3 -> Debug和Release的介绍 3 -> Windows环境调试介绍 3.1 -> 调试环境的准备 3.2 -> 学会快捷键…

不牺牲算法,不挑剔芯片,这个来自中科院的团队正在加速国产AI芯片破局

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 不降低大模型算法精度&#xff0c;还能把芯片的算力利用效率提升 2~10 倍&#xff0c;这就是…

java swing毕业设计题目管理系统eclipse开发Mysql数据库CS结构java编程

一、源码特点 java swing毕业设计题目管理系统 是一套完善的窗体设计系统&#xff0c;对理解SWING java 编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;&#xff0c;系统主要采用C/S模式开发。 应用技术&#xff1a;javamysql 开发工具&#xff…

杨笛一新作:社恐有救了,AI大模型一对一陪聊,帮i人变成e人

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站ai人工智能工具 更多资源欢迎关注 在社交活动中&#xff0c;大语言模型既可以是你的合作伙伴&#xff08;partner&#xff09;&#xff0…

SSL证书价格为什么差异如此大?

SSL证书市场品牌和种类众多&#xff0c;用户在选择证书的时候&#xff0c;也能随心所欲的购买到心仪的证书品牌类型。但是也有不少用户在选购的时候&#xff0c;也不禁有疑问&#xff1a;不同的证书品牌和类型为什么价格相差如此之大&#xff1f;确实&#xff0c;有的证书很便宜…

重磅来袭!2024CWE北京门窗幕墙展

CWE中国&#xff08;北京&#xff09;国际系统门窗及幕墙博览会 CWE China&#xff08;Beijing&#xff09;International System Doors Windows and Curtain Walls Expo 2024 年 8 月 29-31 日 北京&#xff0c;中国国际展览中心顺义馆 展会概况&#xff1a; 2024年CWE中国…

低代码开发平台推荐:国内超好用的十款实测评测

随着互联网技术的飞速发展&#xff0c;低代码平台逐渐成为企业数字化转型的利器。这类平台简化了开发过程&#xff0c;让非专业开发者也能参与到应用构建中来。本文将为您盘点国内十大低代码平台有&#xff1a;Zoho creator、&#xff0c;帮助您更好地选择适合自己企业的低代码…

【目标检测】-入门知识

1、回归与分类问题 回归问题是指给定输入变量(特征)和一个连续的输出变量(标签),建立一个函数来预测输出变量的值。换句话说,回归问题的目标是预测一个连续的输出值,例如预测房价、股票价格、销售额等。回归问题通常使用回归分析技术,例如线性回归、多项式回归、决策树…

Win10系统下的EDGE浏览器启用IE模式

Win10系统下的EDGE浏览器目前已弃用IE内核&#xff0c;这样在访问某些较老的网站会有兼容性问题&#xff0c;本文记录了在EDGE浏览器中启用IE模式的操作方法。 一、启用EDGE浏览器的IE模式 要打开Internet Explorer模式&#xff0c;执行以下步骤: 1、在Microsoft Edge的地址栏…

同城O2O:开发外卖跑腿小程序的技术探索

当下&#xff0c;开发一款功能完善、用户体验良好的外卖跑腿小程序成为了很多互联网企业的首要任务。今天小编将从技术角度对开发外卖跑腿小程序进行探索&#xff0c;为开发者提供一些技术上的思路和方法。 1.技术选型 在开发外卖跑腿小程序时&#xff0c;选择合适的技术栈至关…

Docker使用— Docker部署安装Nginx

Nginx简介 Nginx 是一款高性能的 web 服务器、反向代理服务器以及电子邮件&#xff08;IMAP/POP3/SMTP&#xff09;代理服务器&#xff0c;由俄罗斯开发者伊戈尔塞索耶夫&#xff08;Igor Sysoev&#xff09;编写&#xff0c;并在2004年10月4日发布了首个公开版本0.1.0。Nginx…

C++--运算符重载

运算符重载 在类中重新定义运算符&#xff0c;赋予运算符新的功能以适应类的运算&#xff0c;就称为运算符重载。 运算符重载是一种形式的C多态,它使得对象操作更直观,本质上也是属于函数重载。 实际上&#xff0c;我们已经在不知不觉之中使用了运算符重载。例如&#xff0c;加…

Facebook直播延迟过高是为什么?

在进行Facebook直播 时&#xff0c;高延迟可能会成为一个显著的问题&#xff0c;影响观众的观看体验和互动效果。以下是一些导致Facebook直播延迟过高的可能原因&#xff1a; 1、网络连接问题 网络连接不稳定或带宽不足可能是导致Facebook直播延迟的主要原因之一。如果您的网络…

Jackson 各种注解使用示例

参考资料 Jackson使い方メモ 目录 一. JsonIgnore二. JsonIgnoreProperties三. JsonProperty3.1 作用于entity属性上&#xff0c;指定json对象属性名3.2 作用于entity方法上&#xff0c;指定json对象属性名 四. JsonFormat4.1 日期格式化4.2 数字格式化4.3 枚举类返回code 五.…

限流的实现方式

1、tomcat 设置最大链接数 2、Nginx 漏桶算法 3、网关&#xff0c;令牌桶算法

Linux使用宝塔面板安装MySQL结合内网穿透实现公网连接本地数据库

文章目录 推荐前言1.Mysql服务安装2.创建数据库3.安装cpolar3.2 创建HTTP隧道 4.远程连接5.固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

运筹学基础(六)列生成算法(Column generation)

文章目录 前言从Cutting stock problem说起常规建模Column generation reformulation 列生成法核心思想相关概念Master Problem (MP)Linear Master Problem (LMP)Restricted Linear Master Problem (RLMP)subproblem&#xff08;核能预警&#xff0c;非常重要&#xff09; 算法…

Yalmip使用教程(7)-求解器的参数设置

博客中所有内容均来源于自己学习过程中积累的经验以及对yalmip官方文档的翻译&#xff1a;https://yalmip.github.io/tutorials/ 这篇博客将详细介绍yalmip工具箱中常用的求解器设置选项。 1.求解器的基本设置 使用sdpsettings函数可以对求解的相关参数进行设置。最常用的设置…