关联规则Apriori(python实现):Bakery Bussiness Model
- 数据和编译环境说明
- 数据挖掘目标的建立
- 引入数据(CSV 文件)及相关库
- 数据探索
- 数据清洗
- 深度挖掘数据的深层规律
- 结论
数据和编译环境说明
译文:原文来自https://www.kaggle.com/bbhatt001/bakery-business-model-association-rules,作为个人的学习使用。
数据挖掘目标的建立
那种商品是面包店最畅销的? 面包店是如何运作的? 以下将会用NetworkX来展示运用Apriori算法后频繁集之间的联系。
- NetworkX:python的复杂网络分析库;
- 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')
下一步是探索什么时候面包店的生意最好,从探索的结果来看,白天生意最好,下午和早上生意最繁忙,傍晚和晚上相对较少。
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')
在近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')
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')
下一个图显示了面包店的周销售量。在12月末和1月份的第一周有所严重下滑。
data['Item'].resample('W').count().plot()
plt.ylabel('Number of transactions')
plt.title('Weekly business during the past months')
我进一步放大了面包店的日常表现,发现,12月份末和1月份初有几天的销量为0。
data['Item'].resample('D').count().plot()
plt.ylabel('Number of transactions')
plt.title('Daily business during the past months')
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()
结论
coffee是面包店最畅销的商品,并且与 4种商品- pastry, cake, medialuna and sandwich有关联关系。考虑到coffee与4种商品之间的关系,建议面包店可以采取一些策略来增加销售额。
- 4中商品中的任何一个促销折扣都可以吸引顾客购买咖啡。
- 将这4种商品放在咖啡订购台附近可能会吸引顾客购买。
- 适当得指定一些食谱,如:咖啡蛋糕或咖啡糕点。