基于Python的购物篮频繁项集数据挖掘分析系统

目 录

第一章 绪论 1
1.1 选题背景与研究意义 1
1.2 应用领域 1
1.3 主要研究内容 2
1.4 论文组织结构 2
第二章 理论基础 4
2.1 数据挖掘 4
2.2 频繁项集 5
2.3 关联规则 5
2.4 开发工具及语言 6
2.5 数据准备及预处理 6
第三章 算法实现 8
3.1 Apriori算法 8
3.1.1 Apriori算法简介 8
3.1.2 Apriori算法原理 8
3.1.3 Apriori算法优缺点 12
3.2 Fp-growth算法 12
3.2.1 Fp-growth算法简介 12
3.2.2 Fp-growth算法原理 13
3.2.3 Fp-growth算法优缺点 18
第四章 挖掘关联规则 20
4.1 计算关联规则 20
4.2 结果分析 22
4.3 算法对比 25
第五章 总结与展望 26
5.1 总结 26
5.2 展望 26
致谢 27
参考文献 28
2.2 频繁项集
通常把含有0个或多个项的集合叫作项集,若项集中有N个项,那么它就是N项集。
候选项集:用来获得频繁项集的候选项,它是I中一个或多个项的组合,若包含N个项就成为候选N项集。从候选项集中挑出大于等于min_support的项集,则产生了频繁N项集。
支持度计数:是指项集在总的数据集合中出现的频度,该值对筛选频繁模式和强关联模式起至关重要的作用。
频繁项集:是指总的事务数据集合中频繁出现的项的集合,一般情况,当项集出现的频率满足某一参数时就可以认为它是频繁的,这一参数叫做最小支持度,不满足这一参数的项集叫做非频繁项集。根据以上定义可以得出两个重要定理:
(1)如果一个项集是频繁的,那么它的所有子集也都是频繁的。
(2)如果一个项集是非频繁的,那么它的所有父集都是非频繁的。
2.3 关联规则
关联规则描述的是事务间的联系,若它们有因果关系或者某种特殊规律,我们就称它为关联。设A,B两个集合没有交集,分别代表不同事件,那么称表达式A→B为关联规则。频繁项集挖掘的目的就是发掘出隐藏在数据库中的关联信息,例如超市或电商根据关联分析得出消费者购买某些商品的同时还可能购买哪些商品,或者计算购买某些商品的同时购买另一些商品的概率有多大。
关联规则的产生是基于对历史数据的概率统计而得出的,所以我们需要用一个度量单位来衡量该规则的强度,它就是置信度。置信度用来权衡规则是否可信,支持度主要反映该规则在整个数据集中的权重。
关联规则可以用条件概率来表示,例如规则A→B的支持度可表示为:
(2- 1)
N表示数据集中的总项数。
置信度可表示为:
c(A→B)=σ(A∪B)/σ(A) (2- 2)
同时满足min_support和min_confidence的规则称为有趣规则,一般min_support和min_confidence的取值有相关领域的专家来指定。支持度较低的规则一般都具有较高的偶然性,最小支持度阈值用来过滤掉那些没有意义的规则。最小置信度用来挑选出有趣的关联规则,置信度越高,该规则对生产实践就越具有指导意义。发掘事务集中的频繁模式可分成以下两个步骤:
(1)从候选集中剔除小于min_support的项,留下的就是频繁集。
(2)对频繁集的所有非空子集进行排列组合,构成不同的规则,根据min_confidence阈值,筛选出强关联规则。
通常挖掘频繁项集所耗费的时间远大于计算关联规则所用时间,所以,频繁项集挖掘算法的效率取决于挖掘频繁项集的效率。
2.4 开发工具及语言
本次毕业设计的编码工具采用的是一个轻量、简洁、高效、跨平台的编辑器Sublime Text3,它同时支持Windows/Linux/Mac等操作系统,无需安装,解压即可使用。Sublime Text3支持语法高亮、自动补全、配色等诸多功能,为开发者提供了一个舒适美观的开发环境。它还有良好的扩展功能,只需要安装Package包即可。Sublime Text3所支持的语言也特别丰富,不如主流的C,C++,C#,CSS,HTML,Java,JavaScript,MATLAB,PHP,Python,R,SQL,XML等等,对于这些语言都支持自动补全功能,非常智能。本次毕业设计使用Sublime Text3编写Python代码,目前编写Python代码的开发工具有很多,比如Vim,Eclipse,PyCharm,NotePad++等等,他们都有一个共同的缺点就是重量级,启动速度慢,没有Sublime Text3方便快捷。
Python是一个同时具有解释性、编译性、互动性和面向对象的脚本语言。Python语言语法简单,易于学习,是很多初学者的入门语言。尽管它语法简单,但是它可以实现非常复杂的程序。Python提供了非常完善的内置代码库,覆盖了网络、文件、GUI、数据库等方面,开发过程中,我们不用亲自实现那些功能,只需要调用库函数即可。除了内置库,Python还支持第三方库,别人开发好的用例经过封装之后就可以直接嵌入到自己的代码中使用,同时自己的代码也可以打包封装与别人共享。Python还具有良好的扩展性和嵌入性,我们能把其他语言编写的代码在Python程序中使用,也能将Python代码嵌入到其他语言为其提供脚本服务。Python还支持面向对象编程,与其他面向对象语言相比,Python以一种简单而又强大的方式实现面向对象编程。目前Python的主要应用领域有:云计算、Web开发、人工智能、系统运维以及图形GUI等,尤其是近两年人工智能与机器学习成为热门领域,Python也被越来越多的人使用。目前Python有2.X和3.X两个版本,两者语法上有小小的区别,Python3.X支持了2.X不支持的库,但是大多数Python库是同时支持的。
本次毕业设计采用Python内置的标准库Tkinter编写简单的交互界面。Tkinter可以非常便捷地编写GUI界面,不用安装任何插件,只需要在代码中导入Tkinter库,Python默认编辑器IDLE也是使用Tkinter实现的。
2.5 数据准备及预处理
通常在数据挖掘的完整流程中,数据准备和预处理可能占到六七成的时间,主要针对缺失和异常的数据,以及不同的数据格式。针对数据缺失,通常采用元组删除、数据补齐等方法处理,元组删除是指删除不完整的数据单元,从而使数据集具有完整的信息格式。这种方法并不是最佳的解决策略,它是以牺牲原始数据为代价的,被舍弃的信息严重影响到数据的客观性和挖掘结果的完整性;数据补齐是指用特定的值补充遗漏的信息,通常有均值填补法,特殊值填补法和人工填补法,倘若遗漏的信息是数值类型,则从其余数据中抽取对应元素的值,计算出平均值补到缺失的位置;若是非数值类型,则使用众数原理,将出现最多的值填补进去;特数值法是指将缺失的信息当做一个特殊的值看待,本文转载自http://www.biyezuopin.vip/onews.asp?id=14619但是通常得到的结果偏离了实际;人工填补法是指让了解该数据的人手动填补该数据,这样得到的数据集偏离程度最小,效果也是最好的,但是当数据规模较大的时候,该方法的效率大大降低。异常数据同样可以使用办方法来纠正。
本次毕业设计主要是针对电商及超市等销售行业进行研究讨论,所以数据采用的是某超市一个月的销售订单数据,数据来源于CSDN博客用户分享的Kaggle竞赛公开数据集,数据集中包括销售订单表(order_id,product_id),商品信息表(product_id,product_name,aisle_id,department_id),商品分类表(aisle_id,aisle_name),共计十万多条销售订单。因为是竞赛公开的数据集,所以完备性较高,数据格式是统一的CSV文件格式进行保存的,其数据表的属性比较少,所以在数据处理阶段对于缺少信息的数据直接进行删除。因为订单数据、商品信息和分类信息存储在不同的表中于是在预处理阶段,使用Python将三张表中的信息进行了合并,构成了新的数据表products_aisle(product_id,aisle_id)用于发掘订单数据中商品类别之间的联系。

# !/usr/bin/python
# -*- coding: UTF-8 -*-

import apriori
import fpgrowth
import loaddata
import threading
import Rules
import time
from tkinter import *
from tkinter import scrolledtext
import os
import hashlib
from tkinter import messagebox as tkMessageBox
from tkinter import filedialog as tkFiledialog      


class MY_GUI():

	def __init__(self,window):
		self.window=window
		self.minsupport=0
		self.minconfig=0 
		self.suanfa='FP-Growth'

	
	#设置窗口
	def set_init_window(self):
		self.window.title("第一个GUI界面")      #窗口名
		self.window.geometry('1080x680+10+10')                 #290 160为窗口大小,+10 +10 定义窗口弹出时的默认展示位置
		self.window["bg"] = "pink"                            #窗口背景色,其他背景色见:blog.csdn.net/chl0000/article/details/7657887
		self.init_data_label = Label(self.window, text="待处理数据")
		self.init_data_label.grid(row=0, column=0)
		self.result_data_label = Label(self.window, text="输出结果")
		self.result_data_label.grid(row=0, column=12)
		self.log_label = Label(self.window, text="日志")
		self.log_label.grid(row=12, column=0)
		self.init_data_Text = scrolledtext.ScrolledText(self.window, width=67, height=35,wrap=WORD)  #原始数据录入框
		self.init_data_Text.grid(row=1, column=0, rowspan=10, columnspan=10)
		self.result_data_Text = scrolledtext.ScrolledText(self.window, width=70, height=49,wrap=WORD)  #处理结果展示
		self.result_data_Text.grid(row=1, column=12, rowspan=15, columnspan=10)
		self.log_data_Text = scrolledtext.ScrolledText(self.window, width=66, height=9,wrap=WORD)  # 日志框
		self.log_data_Text.grid(row=13, column=0, columnspan=10)
		#按钮

		Button(self.window,text="清空",command=self.clear_result ,width=8).grid(row=0,column=18)
		Button(self.window,text="清空",command=self.clear_data,width=8).grid(row=0,column=5)

		Button(self.window, text="加载数据集",command=self.click1,  bg="lightblue", width=10).grid(row=1,column=11)  # 调用内部方法  加()为直接调用
		# self.str_trans_to_md5_button.grid(row=1, column=11)
		Button(self.window, text="选择算法",command=lambda:self.click2(), bg="lightblue", width=10).grid(row=2,column=11)  # 调用内部方法  加()为直接调用
 		# # self.str_trans_to_md5_button.grid(row=2, column=11)
		Button(self.window,text="输入参数",command=lambda:self.click3(),bg="lightblue",width=10).grid(row=3,column=11)
		# self.str_trans_to_md5_button
		Button(self.window, text="运行",command=lambda:self.click4(), bg="lightblue", width=10).grid(row=4, column=11)  # 调用内部方法  加()为直接调用
		# self.str_trans_to_md5_button
		Button(self.window,text="生成规则",command=lambda:self.click5(),bg="lightblue",width=10).grid(row=5,column=11)

	def clear_result(self):
		self.result_data_Text.delete(0.0,END)

	def clear_data(self):
		self.init_data_Text.delete(0.0,END)

	def loaddata_thread(self,fn):
		start = time.time()
		self.dataset = loaddata.load_data(fn)
		for i in self.dataset:
			self.init_data_Text.insert(INSERT,str(i))
			self.init_data_Text.insert(INSERT,'\n')
		end = time.time()
		self.log_data_Text.insert(INSERT,'加载完毕!共'+str(len(self.dataset))+'项	耗时:'+str(round(end-start,2))+'s\n')
	def click1(self):
		fn = tkFiledialog.askopenfilename()    #选择文件夹
		if (fn!=''):
			self.log_data_Text.insert(INSERT,'正在加载数据...\n')
			t=threading.Thread(target=self.loaddata_thread,args=(fn,))
			t.setDaemon(True)
			t.start()
		
		

		
	def click2(self):
		self.top = Toplevel()
		self.top.title('选择算法')
		self.top.geometry('150x200')
		self.top['bg']='pink'
		self.top.v = StringVar()
		Radiobutton(self.top,text = 'Aprioi',bg="pink", variable = self.top.v,value = "Aprioi").grid(row=1,column=1,padx=30,pady=10)
		Radiobutton(self.top,text = 'FP-Growth',bg="pink", variable = self.top.v,value = "FP-Growth").grid(row=2,column=1,padx=30,pady=10)
		Button(self.top,text='确定',command=self.clk2_commit).grid(row=3,column=1,padx=30,pady=10)

	def clk2_commit(self):
		self.suanfa=self.top.v.get()
		print(self.suanfa)
		self.top.destroy()

	def click3(self):
		self.top = Toplevel()
		self.top.title('输入参数')
		self.top.geometry('300x200')
		self.top['bg']='pink'
		self.top.v1 = DoubleVar()
		self.top.v2 = DoubleVar()
		Label(self.top,text="最小支持度").grid(row=0,column=0)
		Entry(self.top,textvariable=self.top.v1 ,show=None).grid(row=0,column=1)
		Label(self.top,text="最小置信度").grid(row=1,column=0)
		Entry(self.top,textvariable=self.top.v2 ,show=None).grid(row=1,column=1)
		Button(self.top,text="确定",command=self.clk3_commit).grid(row=2,column=1)

	def clk3_commit(self):
		self.minsupport=self.top.v1.get()
		self.minconfig=self.top.v2.get()
		print(self.minsupport)
		print(self.minconfig)
		self.top.destroy()

	def aprithread(self):
		self.result_data_Text.insert(INSERT,'频繁项集:\n')
		start = time.time()	
		n=0
		if (self.suanfa=='Aprioi'):
			if(self.minsupport!=0):
				self.L,self.support=apriori.apriori(self.dataset,self.minsupport)
			else:
				self.L,self.support=apriori.apriori(self.dataset)
			for x in self.L:
				for i in x:
					self.result_data_Text.insert(INSERT,i)
					self.result_data_Text.insert(INSERT,'\n')
					n+=1

		else:
			self.frozenDataSet = fpgrowth.transfer2FrozenDataSet(self.dataset)
			self.L = {}
			self.prefix = set([])
			if(self.minconfig!=0):
				self.fptree,self.headPointTable = fpgrowth.createFPTree(self.frozenDataSet, self.minsupport)				
				fpgrowth.mineFPTree(self.headPointTable, self.prefix, self.L, self.minsupport)
			else:
				self.fptree,self.headPointTable = fpgrowth.createFPTree(self.frozenDataSet)
				fpgrowth.mineFPTree(self.headPointTable, self.prefix,self.L)
			for i in self.L:
				# print(i)
				self.result_data_Text.insert(INSERT,i)
				self.result_data_Text.insert(INSERT,'\n')
				n+=1
		self.result_data_Text.insert(INSERT,str(n)+'\n')	
		end = time.time()
		self.log_data_Text.insert(INSERT,'频繁项集已生成!	共'+str(n)+'项	耗时:'+str(round(end-start,2))+'s\n')

	def click4(self):
		self.log_data_Text.insert(INSERT,self.suanfa+':正在挖掘频繁项集...\n')
		t=threading.Thread(target=self.aprithread)
		t.setDaemon(True)
		t.start()


	
	def rulesthread(self):
		start = time.time()
		if (self.suanfa=='Aprioi'):
			if(self.minconfig!=0):
				self.rules=apriori.generateRules(self.L,self.support,self.minconfig)
			else:
				self.rules=apriori.generateRules(self.L,self.support)
		else:
			self.rules = []
			if (self.minconfig!=0):
				Rules.rulesGenerator(self.L, self.rules, self.minconfig)
			else:
				Rules.rulesGenerator(self.L, self.rules)
		# self.rules = []
		# if (self.minconfig!=0):
		# 	Rules.rulesGenerator(self.L, self.rules, self.minconfig)
		# else:
		# 	Rules.rulesGenerator(self.L, self.rules)
		self.result_data_Text.insert(INSERT,'关联规则\n')
		for i in self.rules:
			self.result_data_Text.insert(INSERT,list(i))
			self.result_data_Text.insert(INSERT,'\n')
		end = time.time()
		self.result_data_Text.insert(INSERT,str(len(self.rules))+'\n')
		self.log_data_Text.insert(INSERT,'关联规则生成完毕! 共'+str(len(self.rules))+'项	耗时:'+str(round(end-start,2))+'s\n')


	def click5(self):
		self.log_data_Text.insert(INSERT,'正在生成关联规则...\n')
		t=threading.Thread(target=self.rulesthread)
		t.setDaemon(True)
		t.start()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值