草庐IT

Python数据分析案例15——超市零售购物篮关联分析(apriori)

阡之尘埃 2023-10-25 原文

啤酒和纸尿裤的故事大多数人都听说过,纸尿裤的售卖提升了啤酒的销售额。

关联分析就是这样的作用,可以研究某种商品的售卖对另外的商品的销售起促进还是抑制的作用。


案例背景

本次案例背景是超市的零售数据,研究商品之间的关联规则。使用的自然是最经典的apriori算法。

数据展示,数据是一个excel表:

 id表示订单编号,id=1表示第一个订单的销售的商品,如图就是第一个订单卖出了柑橘类水果,人造黄油,即食汤,半成品面包四个商品,其他以此类推。


数据读取

导入包,设置

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

pd.options.display.float_format = '{:,.4f}'.format   #设置小数显示4位
np.set_printoptions(precision=4)
plt.rcParams ['font.sans-serif'] ='SimHei'               #显示中文
plt.rcParams ['axes.unicode_minus']=False               #显示负号

读取案例数据

inputfile = '../data/GoodsOrder.csv'  # 输入的数据文件
data = pd.read_csv(inputfile,encoding = 'gbk')  # 读取数据
data.info()

可以看到是43367条样本。

对商品进行分类汇总,计算每类商品的销售数量,得到前10 的商品

group = data.groupby(['Goods']).count().sort_values('id',ascending=False)            # 对商品进行分类汇总
group.head(10)

 

画柱状图展示;

plt.figure(figsize=(6,3),dpi=128)
sns.barplot(y=group.index[:10],x=group['id'][:10],orient="h")
plt.xlabel('商品订单量')
plt.ylabel('商品名称')
plt.xticks(fontsize=10,rotation=45)
plt.title("销售量前十商品订单数量")
plt.show()

 

 可以看到卖得最多的是全脂牛奶,蔬菜等。


类别分析

读取每种商品对应的类别:

types = pd.read_csv('../data/GoodsTypes.csv',encoding = 'gbk')  # 读入数据
types.head()

 可以看到这个表格包含了所有商品对应的食物的总类别

这个表对上面分类汇总后的订单表进行合并:(放在excel里面实现这一步就是vlookup函数)

sort_links = pd.merge(group.reset_index(),types,on='Goods')  # 合并两个datafreame 
sort_links

 然后我们画出所有大类别商品的销售数量和的比例图:

(sort_links.groupby(['Types']).sum().reset_index()   #分组聚合
.sort_values('id',ascending = False)                #排序
.assign(ratio=lambda d:d['id']/d['id'].sum())[['Types','ratio']]  #计算比例
.set_index('Types').plot                          #画图
.pie(subplots=True,figsize=(8,8),autopct="%.2f%%",legend=False)
)

 可以看到每种大类商品的销售数量比例。


预处理

将原始数据进行合并,每个订单的商品都弄在一起

data['Goods'] = data['Goods'].apply(lambda x:','+x)
data = data.groupby('id').sum().reset_index()
data

 可以看到总共有9835个订单,每个订单里面的商品数量名称都不尽相同。

将上面的订单都变为列表,查看前五个

data['Goods'] = data['Goods'].apply(lambda x :x[1:].split(','))
data_list = list(data['Goods'])
data_list[:5]

 每个订单都是一个列表,装着所有的商品名称,数据准备完成,下面进行关联分析


关联分析

导入包,计算模型,得到结果。这里模型的最小支持度选为0.03,最小置信度选为0.4.

# 导入 apyori 模块下的 apriori 函数
from apyori import apriori
results = apriori(data_list, min_support=0.03, min_confidence=0.4)

打印结果,并装入数据框方便下面画图:

df=pd.DataFrame()
# 遍历结果数据
lis1=[];lis2=[];lis3=[];lis4=[]
for result in results:
    # 获取支持度,并保留3位小数
    support = round(result.support, 3)
    # 遍历ordered_statistics对象
    for rule in result.ordered_statistics:
        # 获取前件和后件并转成列表
        head_set = list(rule.items_base)
        tail_set = list(rule.items_add)
        # 跳过前件为空的数据
        if head_set == []:
                continue
        # 将前件、后件拼接成关联规则的形式
        related_catogory = str(head_set)+'→'+str(tail_set)
        # 提取置信度,并保留3位小数
        confidence = round(rule.confidence, 3)
        # 提取提升度,并保留3位小数
        lift = round(rule.lift, 3)
        # 查看强关联规则,支持度,置信度,提升度
        print(related_catogory, support, confidence, lift)
        lis1.append(related_catogory);lis2.append(support)
        lis3.append(confidence);lis4.append(lift)

 可以看到最终得到了5个关联规则。

变成数据框

df['related_catogory']=lis1
df['support']=lis2
df['confidence']=lis3
df['lift']=lis4
df=df.sort_values('lift',ascending = False)
df

 画图之前要对数据做一点变形,使用数据融合

df_bar=pd.melt(df,id_vars=['related_catogory'],var_name='变量名称',value_name='变量值')
df_bar

 或者数据堆叠方法,也是一样的效果:

#或者
df.set_index('related_catogory').stack().reset_index()

 画柱状图:(不喜欢这个颜色可以改palette这个参数。)

plt.figure(figsize=(9,3),dpi=128)
sns.barplot(x=df_bar.related_catogory,y=df_bar.变量值,hue=df_bar.变量名称,palette = "twilight")
plt.xticks(fontsize=8,rotation=10)
plt.xlabel('关联规则')
plt.show()

 5个关联规则对应的支持度,置信度,提升度都在这个图上了。


结论 

本次分析得到,买根‘’茎类蔬菜' 会促进['其他蔬菜']的销售量,其提升度最大,为2.247。

同样买['酸奶']会促进['全脂牛奶']的销售量。

买['根茎类蔬菜']促进['全脂牛奶']的销售量。

['热带水果']→['全脂牛奶']

['酸奶']→['全脂牛奶']

有关Python数据分析案例15——超市零售购物篮关联分析(apriori)的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  6. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  7. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  8. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  9. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  10. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

随机推荐