关联规则Apriori(python实现):Bakery Bussiness Model

  • 数据和编译环境说明
  • 数据挖掘目标的建立
  • 引入数据(CSV 文件)及相关库
  • 数据探索
  • 数据清洗
  • 深度挖掘数据的深层规律
  • 结论


数据和编译环境说明

译文:原文来自https://www.kaggle.com/bbhatt001/bakery-business-model-association-rules,作为个人的学习使用。

数据挖掘目标的建立

那种商品是面包店最畅销的? 面包店是如何运作的? 以下将会用NetworkX来展示运用Apriori算法后频繁集之间的联系。

  1. NetworkX:python的复杂网络分析库;
  2. Apriori算法的原理:https://yq.aliyun.com/articles/180610?spm=5176.10695662.1996646101.searchclickresult.7bfb4563WBIYwe;

引入数据(CSV 文件)及相关库

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, association_rules
import networkx as nx
import warnings
warnings.filterwarnings('ignore')

数据探索

这里总共有21193行,4列数据

data=pd.read_csv('../input/BreadBasket_DMS.csv')
data.head()

‘’

Date

Time

Transaction

Item

0

2016-10-30

09:58:11

1

Bread

1

2016-10-30

10:05:34

2

Scandinavian

2

2016-10-30

10:05:34

2

Scandinavian

3

2016-10-30

10:07:57

3

Hot chocolate

4

2016-10-30

10:07:57

3

Jam

data.shape

(21293,4)

data.describe()

‘’

Transaction

count

21293.000000

mean

4951.990889

std

2787.758400

min

1.000000

25%

2548.000000

50%

5067.000000

75%

7329.000000

max

9684.000000

data.info()

<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 21293 entries, 0 to 21292
Data columns (total 4 columns):
Date 21293 non-null object
Time 21293 non-null object
Transaction 21293 non-null int64
Item 21293 non-null object
dtypes: int64(1), object(3)
memory usage: 665.5+ KB

数据清洗

在数据探索的过程中发现,虽然没有明显的空值,但有一些标记为“NONE”的数据,因此我将移除待“NONE”标记的数据。

data.loc[data['Item']=='NONE',:].count()

Date 786
Time 786
Transaction 786
Item 786
dtype: int64

data=data.drop(data.loc[data['Item']=='NONE'].index) #删除带NONE标志的数据

接下来想到就是:这个面包店都有卖哪几种商品呢?答案是94种。

data['Item'].nunique()

94

data['Item'].value_counts().sort_values(ascending=False).head(10)

Coffee 5471
Bread 3325
Tea 1435
Cake 1025
Pastry 856
Sandwich 771
Medialuna 616
Hot chocolate 590
Cookies 540
Brownie 379
Name: Item, dtype: int64

fig, ax=plt.subplots(figsize=(6,4))
data['Item'].value_counts().sort_values(ascending=False).head(10).plot(kind='bar')
plt.ylabel('Number of transactions')
plt.xlabel('Items')
ax.get_yaxis().get_major_formatter().set_scientific(False)
plt.title('Best sellers')

python生成关联规则 python关联规则代码_ci

下一步是探索什么时候面包店的生意最好,从探索的结果来看,白天生意最好,下午和早上生意最繁忙,傍晚和晚上相对较少。

data.loc[(data['Time']<'12:00:00'),'Daytime']='Morning'
data.loc[(data['Time']>='12:00:00')&(data['Time']<'17:00:00'),'Daytime']='Afternoon'
data.loc[(data['Time']>='17:00:00')&(data['Time']<'21:00:00'),'Daytime']='Evening'
data.loc[(data['Time']>='21:00:00')&(data['Time']<'23:50:00'),'Daytime']='Night'
fig, ax=plt.subplots(figsize=(6,4))
sns.set_style('darkgrid')
data.groupby('Daytime')['Item'].count().sort_values().plot(kind='bar')
plt.ylabel('Number of transactions')
ax.get_yaxis().get_major_formatter().set_scientific(False)
plt.title('Business during the day')

python生成关联规则 python关联规则代码_Time_02

在近6个月当中,在下午(12:0017:00)面包店总共售商品11569件;在晚上(21:0024:00),共售商品14件。

data.groupby('Daytime')['Item'].count().sort_values(ascending=False)

Daytime
Afternoon 11569
Morning 8404
Evening 520
Night 14
Name: Item, dtype: int64

进一步分析,每个月一天当中具体的运作情况

data['Date_Time']=pd.to_datetime(data['Date']+' '+data['Time'])
data['Day']=data['Date_Time'].dt.day_name()
data['Month']=data['Date_Time'].dt.month
data['Month_name']=data['Date_Time'].dt.month_name()
data['Year']=data['Date_Time'].dt.year
data['Year_Month']=data['Year'].apply(str)+' '+data['Month_name'].apply(str)
data.drop(['Date','Time'], axis=1, inplace=True)

data.index=data['Date_Time']
data.index.name='Date'
data.drop(['Date_Time'],axis=1,inplace=True)
data.head()

Date

Transaction

Item

Daytime

Day

Month

Month_name

Year

Year_Month

2016-10-30 09:58:11

1

Bread

Morning

Sunday

10

October

2016

2016 October

2016-10-30 10:05:34

2

Scandinavian

Morning

Sunday

10

October

2016

2016 October

2016-10-30 10:05:34

2

Scandinavian

Morning

Sunday

10

October

2016

2016 October

2016-10-30 10:07:57

3

Hot chocolate

Morning

Sunday

10

October

2016

2016 October

2016-10-30 10:07:57

3

Jam

Morning

Sunday

10

October

2016

2016 October

下图展示了面包店在不同月份的销售情况,从图中可知:11、4月份生意最少,主要原因是因为这两个月开张天数分别是2、7天。

data.groupby('Year_Month')['Item'].count().plot(kind='bar')
plt.ylabel('Number of transactions')
plt.title('Business during the past months')

python生成关联规则 python关联规则代码_Apriori算法_03

data.loc[data['Year_Month']=='2016 October'].nunique()

Transaction 175
Item 30
Daytime 3
Day 2
Month 1
Month_name 1
Year 1
Year_Month 1
dtype: int64

data.loc[data['Year_Month']=='2017 April'].nunique()

Transaction 509
Item 49
Daytime 4
Day 7
Month 1
Month_name 1
Year 1
Year_Month 1
dtype: int64

_下一步,着力去寻找每个月销量最高的商品。下面这个表格不仅显示了具有最多买家的商品,还检查了他们感兴趣的商品的销售数量。正如表中的数据可得,咖啡在所有月份都是最畅销的。

data2=data.pivot_table(index='Month_name',columns='Item', aggfunc={'Item':'count'}).fillna(0)
data2['Max']=data2.idxmax(axis=1)
data2

Item … Max
Item Adjustment …
Month_name …
1 0.0 … (Item, Coffee)
2 0.0 … (Item, Coffee)
3 0.0 … (Item, Coffee)
4 0.0 … (Item, Coffee)
10 0.0 … (Item, Coffee)
11 1.0 … (Item, Coffee)
12 0.0 … (Item, Coffee)

接下来找日销售最高的商品。 早上、中午和晚上,咖啡的销量是最高的;理由很显然,晚上咖啡不是太受大家欢迎。Vegan feast在晚上是最畅销的。

data3=data.pivot_table(index='Daytime',columns='Item', aggfunc={'Item':'count'}).fillna(0)
data3['Max']=data3.idxmax(axis=1)
data3

Item … Max
Item Adjustment …
Daytime …
Afternoon 0.0 … (Item, Coffee)
Evening 1.0 … (Item, Coffee)
Morning 0.0 … (Item, Coffee)
Night 0.0 … (Item, Vegan Feast)

和预想的一样,咖啡从星期一到星期天都是畅销的。

data4=data.pivot_table(index='Day',columns='Item', aggfunc={'Item':'count'}).fillna(0)
data4['Max']=data4.idxmax(axis=1)
data4

Item … Max
Item Adjustment …
Day …
Friday 0.0 … (Item, Coffee)
Monday 0.0 … (Item, Coffee)
Saturday 0.0 … (Item, Coffee)
Sunday 0.0 … (Item, Coffee)
Thursday 0.0 … (Item, Coffee)
Tuesday 0.0 … (Item, Coffee)
Wednesday 1.0 … (Item, Coffee)

面包店的业务不断增长引起了我的注意,为进一步探索,我绘制了一些折线图。通过观察上面的柱形图,11月的业务量最大,其次是2月、3月,而12月、1月的业绩有所下降。

data['Item'].resample('M').count().plot()
plt.ylabel('Number of transactions')
plt.title('Business during the past months')

python生成关联规则 python关联规则代码_python生成关联规则_04

下一个图显示了面包店的周销售量。在12月末和1月份的第一周有所严重下滑。

data['Item'].resample('W').count().plot()
plt.ylabel('Number of transactions')
plt.title('Weekly business during the past months')

python生成关联规则 python关联规则代码_Time_05

我进一步放大了面包店的日常表现,发现,12月份末和1月份初有几天的销量为0。

data['Item'].resample('D').count().plot()
plt.ylabel('Number of transactions')
plt.title('Daily business during the past months')

python生成关联规则 python关联规则代码_Apriori算法_06

data['Item'].resample('D').count().max()

292

深度挖掘数据的深层规律

注:这里的Apriori算法不再赘述。

Apriori算法是用于进一步提取关联规则中的频繁项集。在此算法中,用户定义最小支持度,用于决定项集是否被视为频繁的最小阈值。

首先我做了一个包含几个商品一起购买的数据表,来做关联分析

lst=[]
for item in data['Transaction'].unique():
    lst2=list(set(data[data['Transaction']==item]['Item']))
    if len(lst2)>0:
        lst.append(lst2)
print(lst[0:3])
print(len(lst))

[[‘Bread’], [‘Scandinavian’], [‘Cookies’, ‘Hot chocolate’, ‘Jam’]]
9465

将数据采用独热编码(one -hot enconding)进行转换后,才能使用Apriori算法。这里将调用TransacitionEncoder进行数据的转化,然后调用Apriori算法获取频繁项集。最后使用关联规则函数(可使用任意一种度量方法),此处使用“lift”,其最小阈值为1.

te=TransactionEncoder()
te_data=te.fit(lst).transform(lst)
data_x=pd.DataFrame(te_data,columns=te.columns_)
print(data_x.head())

frequent_items= apriori(data_x, use_colnames=True, min_support=0.03)
print(frequent_items.head())

rules = association_rules(frequent_items, metric="lift", min_threshold=1)
rules.antecedents = rules.antecedents.apply(lambda x: next(iter(x)))
rules.consequents = rules.consequents.apply(lambda x: next(iter(x)))
rules

Adjustment … Victorian Sponge
0 False … False
1 False … False
2 False … False
3 False … False
4 False … False

[5 rows x 94 columns]
support itemsets
0 0.036344 (Alfajores)
1 0.327205 (Bread)
2 0.040042 (Brownie)
3 0.103856 (Cake)
4 0.478394 (Coffee)

Out[18]:
antecedents consequents … leverage conviction
0 Cake Coffee … 0.005044 1.102664
1 Coffee Cake … 0.005044 1.011905
2 Medialuna Coffee … 0.005614 1.210871
3 Coffee Medialuna … 0.005614 1.012667
4 Coffee Sandwich … 0.003877 1.008807
5 Sandwich Coffee … 0.003877 1.115384
6 Coffee Pastry … 0.006351 1.014740
7 Pastry Coffee … 0.006351 1.164682
[8 rows x 9 columns]

下一步使用NetworkX去构建一个网络图,该网络图用于建立相互之间有因果关系的图形。从图中可知,coffee最畅销的时候,pastry, cake, medialuna 和sandwich也一起被购买。所以,如果有人4种商品的任意一种,那么其购买coffee的概率也很高。

fig, ax=plt.subplots(figsize=(10,4))
GA=nx.from_pandas_edgelist(rules,source='antecedents',target='consequents')
nx.draw(GA,with_labels=True)
plt.show()

python生成关联规则 python关联规则代码_Apriori算法_07

结论

coffee是面包店最畅销的商品,并且与 4种商品- pastry, cake, medialuna and sandwich有关联关系。考虑到coffee与4种商品之间的关系,建议面包店可以采取一些策略来增加销售额。

  1. 4中商品中的任何一个促销折扣都可以吸引顾客购买咖啡。
  2. 将这4种商品放在咖啡订购台附近可能会吸引顾客购买。
  3. 适当得指定一些食谱,如:咖啡蛋糕或咖啡糕点。