欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 python数据分析实战之超市零售分析

程序员文章站 2022-11-01 21:54:07
文章目录1、明确需求和目的2、数据收集3、数据预处理3.1 数据整合3.1.1 加载相关库和数据集3.1.2 数据概览3.2 数据清洗3.2.1 列名重命名3.2.2 数据类型处理3.2.3 缺失值处理3.2.4 异常值处理3.2.5 重复值处理4、数据分析4.1 整体销售情况分析4.1.1 销售额分析4.1.2 销量分析4.1.3 利润分析4.1.4 客单价分析4.1.5 市场布局分析4.2 商品情况分析4.3 用户情况分析4.3.1 不同类型的客户占比4.3.2 客户下单行为分析4.3.3 RFM模型...

1、明确需求和目的

  • 对一家全球超市四年(2011-2014)的销售数据进行 “人、货、场”分析,并给出提升销量的针对性建议。
  • 场:整体运营情况分析,包括销售额、销量、利润、客单价、市场布局等具体情况分析。
  • 货:商品结构、优势/爆款商品、劣势/待优化商品等情况分析。
  • 人:客户数量、新老客户、RFM模型、复购率、回购率等用户行为分析。

2、数据收集

  • 数据来源为kaggle平台,这是一份全球大型超市四年的零售数据集,数据详尽。
  • 数据集为 “superstore_dataset2011-2015.csv”,共有51290条数据,共24个特征。

3、数据预处理

3.1 数据整合
3.1.1 加载相关库和数据集
  • 使用的库主要有:pandas、numpy、matplotlib、seaborn
  • 使用的数据集:superstore_dataset2011-2015.csv
# 加载数据分析需要使用的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings

plt.rcParams['font.sans-serif'] = ['SimHei']
warnings.filterwarnings('ignore')


# 加载零售数据集,使用'ISO-8859-1'编码方式
df = pd.read_csv('superstore_dataset2011-2015.csv',encoding='ISO-8859-1') 
df.head()

荐
                                                        python数据分析实战之超市零售分析

3.1.2 数据概览

首先看一下数据集大小(行列信息):

df.shape
---------------
(51290, 24)

看一下数据概况:

# df.info()
df.describe()

荐
                                                        python数据分析实战之超市零售分析

3.2 数据清洗
3.2.1 列名重命名

从上面发现列名不符合Python的命名规范,对列名进行一下重命名,采用下划线命名法:

df.rename(columns = lambda x: x.replace(' ', '_').replace('-', '_'), inplace=True)

看一下重命名后的列名:

df.columns
-----------------
Index(['Row_ID', 'Order_ID', 'Order_Date', 'Ship_Date', 'Ship_Mode',
       'Customer_ID', 'Customer_Name', 'Segment', 'City', 'State', 'Country',
       'Postal_Code', 'Market', 'Region', 'Product_ID', 'Category',
       'Sub_Category', 'Product_Name', 'Sales', 'Quantity', 'Discount',
       'Profit', 'Shipping_Cost', 'Order_Priority'],
      dtype='object')
3.2.2 数据类型处理

查看一下各个列的数据类型:

df.dtypes
-----------------
Row_ID              int64
Order_ID           object
Order_Date         object
Ship_Date          object
Ship_Mode          object
Customer_ID        object
Customer_Name      object
Segment            object
City               object
State              object
Country            object
Postal_Code       float64
Market             object
Region             object
Product_ID         object
Category           object
Sub_Category       object
Product_Name       object
Sales             float64
Quantity            int64
Discount          float64
Profit            float64
Shipping_Cost     float64
Order_Priority     object
dtype: object

从上面看到,大部分为object类型,销量、销售额、利润等为数值型,不需要进行数据类型处理。下单日期应为datetime类型,需要进行处理。

df["Order_Date"] = pd.to_datetime(df["Order_Date"]) 
df["Order_Date"].sample(5)
----------------------------------
9319    2013-04-10
30390   2012-03-19
31025   2013-08-19
32210   2014-03-20
43430   2012-11-26
Name: Order_Date, dtype: datetime64[ns]

为了便于分析每年和每月的销售情况,增加年份列和月份列:

df['year'] = df["Order_Date"].dt.year
df['month'] = df['Order_Date'].values.astype('datetime64[M]')
3.2.3 缺失值处理

查看缺失值情况:

df.isnull().sum(axis=0)
----------------------------
Row_ID                0
Order_ID              0
Order_Date            0
Ship_Date             0
Ship_Mode             0
Customer_ID           0
Customer_Name         0
Segment               0
City                  0
State                 0
Country               0
Postal_Code       41296
Market                0
Region                0
Product_ID            0
Category              0
Sub_Category          0
Product_Name          0
Sales                 0
Quantity              0
Discount              0
Profit                0
Shipping_Cost         0
Order_Priority        0
year                  0
month                 0
dtype: int64

发现有一列缺失值比较多,此列表示邮编信息,对我们的分析没有太多作用,可直接删除:

df.drop(["Postal_Code"],axis=1, inplace=True)
3.2.4 异常值处理

简单查看一下是否有异常值:

df.describe()

荐
                                                        python数据分析实战之超市零售分析

没发现明显的异常值,不需要进行处理。

3.2.5 重复值处理

看一下是否有重复值:

df.duplicated().sum()
---------------------
0

也没有重复值,不需要进行处理。

4、数据分析

4.1 整体销售情况分析

首先构造整体销售情况子数据集:

# 整体销售情况子数据集,包含下单日期、销售额、销量、利润、年份、月份信息
sales_data = df[['Order_Date','Sales','Quantity','Profit','year','month']]
sales_data.sample(5)  
------------------------------
		Order_Date	Sales	Quantity	Profit	year	month
45436	2014-11-27	38.040	2			12.1728	2014	2014-11-01
12625	2013-11-11	20.368	1			7.3834	2013	2013-11-01
24800	2011-11-15	40.320	7			14.0000	2011	2011-11-01
35508	2014-01-22	27.936	4			9.4284	2014	2014-01-01
39183	2013-06-24	179.880	6			61.0800	2013	2013-06-01

按照年份、月份对销售子数据集进行分组求和:

sales_year = sales_data.groupby(['year','month']).sum()
sales_year

荐
                                                        python数据分析实战之超市零售分析

对以上数据进行拆分,每年为一个表:

#  slice(None), 是Python中的切片操作,这里用来选择全部数据
year_2011 = sales_year.loc[(2011,slice(None)),:].reset_index()
year_2012 = sales_year.loc[(2012,slice(None)),:].reset_index()
year_2013 = sales_year.loc[(2013,slice(None)),:].reset_index()
year_2014 = sales_year.loc[(2014,slice(None)),:].reset_index()
year_2014    # 看一下2014年的数据

荐
                                                        python数据分析实战之超市零售分析

4.1.1 销售额分析

构建销售表:

sales=pd.concat([year_2011['Sales'],year_2012['Sales'],
                 year_2013['Sales'],year_2014['Sales']],axis=1)

# 对行名和列名进行重命名
sales.columns=['Sales-2011','Sales-2012','Sales-2013','Sales-2014']
sales.index=['Jau','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

# 颜色越深,销售额越高
sales.style.background_gradient()

荐
                                                        python数据分析实战之超市零售分析

从上图可以看出,基本上每一年都是下半年销售额比上半年要高,而且随着年份的增大,销售额也有明显的增加,说明销售业绩增长较快,发展还是比较好的。

肉眼可见的是每一年的销售额都比前一年要好,来实际计算一下具体的增长率和每年的销售总额:

# 计算年度销售额并图表展示
sales_sum=sales.sum()
sales_sum.plot(kind='bar',alpha=0.5)
plt.grid()

# 计算每年增长率
rise_12=sales_sum[1]/sales_sum[0]-1
rise_13=sales_sum[2]/sales_sum[1]-1
rise_14=sales_sum[3]/sales_sum[2]-1
rise_rate=[0,rise_12,rise_13,rise_14]

# 显示增长率
sales_sum=pd.DataFrame({'sales_sum':sales_sum})
sales_sum['rise_rate']=rise_rate
sales_sum
------------------------------------------
				sales_sum	rise_rate
Sales-2011	2.259451e+06	0.000000
Sales-2012	2.677439e+06	0.184995
Sales-2013	3.405746e+06	0.272017
Sales-2014	4.299866e+06	0.262533

荐
                                                        python数据分析实战之超市零售分析

从上面可以看出,后两年的销售额增长率达到26%,2014年销售额将近是2011的两倍,发展势头良好,经营在逐步稳定。结合年度销售额及增长率,再结合公司整体战略规划,可以预测或制定下一年度总销售额业绩指标。

了解了超市整体销售额后,再对每年每月的销售额进行分析,了解不同月份的销售情况,找出是否有淡旺季之分,找出重点销售月份,以便制定经营策略与业绩月度及季度指标拆分。

看一下销售额的面积堆叠图:

# 面积堆叠图
sales.plot.area(stacked=False)

荐
                                                        python数据分析实战之超市零售分析

从上图可以大致看出,该超市的销售季节性明显,总体上半年是淡季,下半年是旺季。上半年中6月份销售额比较高,下半年中7月份的销售额偏低。

  • 对于旺季的月份,运营推广等策略要继续维持,还可以加大投入,提高整体销售额。
  • 对于淡季的月份,可以结合产品特点进行新产品拓展,举办一些促销活动等吸引客户。
4.1.2 销量分析

构建销量表:

quantity = pd.concat([year_2011['Quantity'],year_2012['Quantity'],
                 year_2013['Quantity'],year_2014['Quantity']],axis=1)

# 对行名和列名进行重命名
quantity.columns=['Quantity-2011','Quantity-2012','Quantity-2013','Quantity-2014']
quantity.index=['Jau','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

# 颜色越深,销量越高
quantity.style.background_gradient()

荐
                                                        python数据分析实战之超市零售分析

看一下销量增长率和每年的销量总和:

# 计算年度销量并图表展示
quantity_sum=quantity.sum()
quantity_sum.plot(kind='bar',alpha=0.5)
plt.grid()

# 计算每年增长率
rise_12=quantity_sum[1]/quantity_sum[0]-1
rise_13=quantity_sum[2]/quantity_sum[1]-1
rise_14=quantity_sum[3]/quantity_sum[2]-1
rise_rate=[0,rise_12,rise_13,rise_14]

# 显示增长率
quantity_sum=pd.DataFrame({'quantity_sum':quantity_sum})
quantity_sum['rise_rate']=rise_rate
quantity_sum
------------------------------
			quantity_sum	rise_rate
Quantity-2011	31443	0.000000
Quantity-2012	38111	0.212066
Quantity-2013	48136	0.263047
Quantity-2014	60622	0.259390

荐
                                                        python数据分析实战之超市零售分析

从上面可以看出,2011-2014年销量变化趋势与销售额是一样的,下半年销量整体高于上半年,同时销量同比上一年均在提高。

4.1.3 利润分析

构建利润表:

profit=pd.concat([year_2011['Profit'],year_2012['Profit'],
                 year_2013['Profit'],year_2014['Profit']],axis=1)
profit.columns=['Profit-2011','Profit-2012','Profit-2013','Profit-2014']
profit.index=['Jau','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

profit.style.background_gradient()

荐
                                                        python数据分析实战之超市零售分析

计算每年总利润和利润率:

# 计算年度总利润并图表展示
profit_sum=profit.sum()
profit_sum.plot(kind='bar',alpha=0.5)
plt.grid()

profit_sum=pd.DataFrame({'profit_sum':profit_sum})
profit_sum["year"] =  [2011, 2012, 2013, 2014]

sales_sum=pd.DataFrame({'sales_sum':sales.sum()})
sales_sum["year"] =  [2011, 2012, 2013, 2014]

profit_sum = pd.merge(profit_sum, sales_sum)
profit_sum["profit_rate"] = profit_sum["profit_sum"] / profit_sum["sales_sum"]
profit_sum
-----------------------------
		profit_sum	year	sales_sum	profit_rate
0	248940.81154	2011	2.259451e+06	0.110178
1	307415.27910	2012	2.677439e+06	0.114817
2	406935.23018	2013	3.405746e+06	0.119485
3	504165.97046	2014	4.299866e+06	0.117252

荐
                                                        python数据分析实战之超市零售分析

从上面的结果可以看出,每年的利润和销售额一样,是在逐年增加的,说明企业经营还是比较妥善的,但是利润率总体平稳,稳定在11%-12%之间,总体利润率也还是不错的。

4.1.4 客单价分析

客单价是指商场(超市)每一个顾客平均购买商品的金额,客单价也即是平均交易金额。从某种程度上反映了企业的消费群体的许多特点以及企业的销售类目的盈利状态是否健康。

总消费次数:同一天内,同一个人发生的所有消费算作一次消费。

客单价=总消费金额 / 总消费次数

# 2011-2014年客单价
for i in range(2011,2015):
    data=df[df['year']==i]
    price=data[['Order_Date','Customer_ID','Sales']]

    # 计算总消费次数
    price_dr=price.drop_duplicates(
        subset=['Order_Date', 'Customer_ID'])

    # 总消费次数:有多少行
    total_num=price_dr.shape[0]
    print('{}年总消费次数='.format(i),total_num)

    unit_price = price['Sales'].sum()/total_num
    print('{}年客单价='.format(i), unit_price,'\n')
---------------------------------------------------
2011年总消费次数= 4453
2011年客单价= 507.3997070604087 

2012年总消费次数= 5392
2012年客单价= 496.55762136498515 

2013年总消费次数= 6753
2013年客单价= 504.3308824788983 

2014年总消费次数= 8696
2014年客单价= 494.4647965225392 

从上面结果来看,每年的消费次数呈不断上升趋势,但是客单价总体浮动范围不是很大 ,稳定在500左右。

4.1.5 市场布局分析

因为这是一家全球超市,在不同地区都会有市场,所以看一下不同地区之间的销售情况:

Market_Year_Sales = df.groupby(['Market', 'year']).agg({'Sales':'sum'}).reset_index().rename(columns={'Sales':'Sales_amounts'})
Market_Year_Sales.head()
--------------------------------
	Market	year	Sales_amounts
0	APAC	2011	6.392453e+05
1	APAC	2012	7.627193e+05
2	APAC	2013	9.745809e+05
3	APAC	2014	1.209199e+06
4	Africa	2011	1.271873e+05

用图表显示各个地区每年的销售情况:

sns.barplot(x='Market', y='Sales_amounts', hue='year', data = Market_Year_Sales)
plt.title('2011-2014 market sales')

荐
                                                        python数据分析实战之超市零售分析

再看一下四年来各个地区销售额占总销售额的百分比:

Market_Sales = df.groupby(['Market']).agg({'Sales':'sum'})
Market_Sales["percent"] = Market_Sales["Sales"] / df["Sales"].sum()
Market_Sales.style.background_gradient()

荐
                                                        python数据分析实战之超市零售分析

从以上图表可以看出,每个地区每年销售额总体处于上升趋势,其中APAC(亚太地区)、EU(欧盟)、US(美国)、LATAM(拉丁美洲)的销售额超过了总销售额的85%,总体也与地区的经济发展相匹配。其中加拿大Canada的销售额微乎其微,可以结合公司整体战略布局进行取舍。

4.2 商品情况分析

先看一下销量前10名的商品:

productId_count = df.groupby('Product_ID').count()['Customer_ID'].sort_values(ascending=False)
print(productId_count.head(10))
--------------------------------------
Product_ID
OFF-AR-10003651    35
OFF-AR-10003829    31
OFF-BI-10002799    30
OFF-BI-10003708    30
FUR-CH-10003354    28
OFF-BI-10002570    27
OFF-BI-10004140    25
OFF-BI-10004195    24
OFF-BI-10001808    24
OFF-BI-10004632    24
Name: Customer_ID, dtype: int64

销售额前10名的商品:

productId_amount = df.groupby('Product_ID').sum()['Sales'].sort_values(ascending=False)
print(productId_amount.head(10))
-----------------------------------
Product_ID
TEC-CO-10004722    61599.8240
TEC-PH-10004664    30041.5482
OFF-BI-10003527    27453.3840
TEC-MA-10002412    22638.4800
TEC-PH-10004823    22262.1000
FUR-CH-10002024    21870.5760
FUR-CH-10000027    21329.7300
OFF-AP-10004512    21147.0840
FUR-TA-10001889    20730.7557
OFF-BI-10001359    19823.4790
Name: Sales, dtype: float64

从上面可以看出,销量最高的大部分是办公用品,而销售额最高的大部分是电子产品、家具这些单价较高的商品。

利润前10的商品:

productId_Profit= df.groupby('Product_ID').sum()['Profit'].sort_values(ascending=False)
print(productId_Profit.head(10))
------------------------------------
Product_ID
TEC-CO-10004722    25199.9280
OFF-AP-10004512    10345.5840
TEC-PH-10004823     8121.4800
OFF-BI-10003527     7753.0390
TEC-CO-10001449     6983.8836
FUR-CH-10002250     6123.2553
TEC-PH-10004664     5455.9482
OFF-AP-10002330     5452.4640
TEC-PH-10000303     5356.8060
FUR-CH-10002203     5003.1000
Name: Profit, dtype: float64

利润前10的商品有一半是电子产品,可以重点考虑提升这部分产品的销量,来增加整体的利润。

具体商品种类的销售情况:

# 根据商品种类和子种类,重新重合成一个新的种类
df['Category_Sub_Category'] = df[['Category','Sub_Category']].apply(lambda x:str(x[0])+'_'+str(x[1]),axis=1)
# 按照新的种类进行分组,统计销售额和利润
df_Category_Sub_Category=df.groupby("Category_Sub_Category").agg({"Profit":"sum","Sales":"sum"}).reset_index()
# 按照销售额倒序排序
df_Category_Sub_Category.sort_values(by=["Sales"],ascending=False, inplace=True)
# 每个种类商品的销售额累计占比
df_Category_Sub_Category['cum_percent'] = df_Category_Sub_Category['Sales'].cumsum()/df_Category_Sub_Category['Sales'].sum()
df_Category_Sub_Category

荐
                                                        python数据分析实战之超市零售分析

从图表中可以很清晰的看到不同种类商品的销售额贡献对比,有将近一半的商品的总销售占比达到84%,应该是自家优势主营产品,后续经营中应继续保持,可以结合整体战略发展适当加大投入,逐渐形成自己的品牌。

同时,也可以发现,末尾占比16%的产品中大部分是办公用品中的小物件。可以考虑与其他主营产品结合,连带销售来提升销量,或者考虑对这些商品进行优化。

但是值得关注的是,Tables(桌子)的利润是负,表明这个产品目前处于亏损状态,应该是促销让利太多。通过检查原数据,发现Tabels大部分都在打折,打折的销量高达76%。如果是在清库存,这个效果还是不错的,但如果不是,说明这个产品在市场推广上遇到了瓶颈,或者是遇到强竞争对手,需要结合实际业务进行分析,适当改善经营策略。

4.3 用户情况分析
4.3.1 不同类型的客户占比
df["Segment"].value_counts().plot(kind='pie', autopct='%.2f%%', shadow=True, figsize=(14, 6))

荐
                                                        python数据分析实战之超市零售分析

从上图可以看出,这四年来,普通消费者的客户占比最多,达到51.7%。

再看一下每一年不同类型的客户数量情况:

Segment_Year = df.groupby(["Segment", 'year']).agg({'Customer_ID':'count'}).reset_index()
sns.barplot(x='Segment', y='Customer_ID', hue='year', data = Segment_Year)
plt.title('2011-2014 Segment Customer')

荐
                                                        python数据分析实战之超市零售分析

从上面可以看出,每类客户每年均在保持增长趋势,客户结构还是非常不错的。

看一下不同类型的客户每年贡献的销售额:

Segment_sales = df.groupby(["Segment", 'year']).agg({'Sales':'sum'}).reset_index()
sns.barplot(x='Segment', y='Sales', hue='year', data = Segment_sales)
plt.title('2011-2014 Segment Sales')

荐
                                                        python数据分析实战之超市零售分析

各个类型的客户每年贡献的销售额都在稳步提升,普通消费者贡献的销售额最多,这和客户占比也有一定关系。

4.3.2 客户下单行为分析

首先截取Customer_ID, Order_Date, Quantity, Sales, month为新的子集,并对Order_Date进行排序,方便后续分析 :

grouped_Customer = df[['Customer_ID','Order_Date', 
          'Quantity', 'Sales', 'month']].sort_values(['Order_Date']).groupby('Customer_ID')
grouped_Customer.head()

荐
                                                        python数据分析实战之超市零售分析

看一下用户的第一次购买日期分布:

grouped_Customer.min().Order_Date.value_counts().plot()

荐
                                                        python数据分析实战之超市零售分析
再来看一下用户的最后一次购买日期分布:

grouped_Customer.max().Order_Date.value_counts().plot()

荐
                                                        python数据分析实战之超市零售分析

从上面可以看出, 在13年初以后新用户增长的趋势缓慢,商家可以通过广告等推广策略吸收更多的新用户;而通过观察最近一次购买日期,可以发现用户基本没有流失,也验证了每年销售额的增长趋势。

总体来说新客户数量是在逐年递减的,说明该企业老客户的维系不错,但新客获取率较低。如果能够在新客户获取上能够突破,会给企业带来很大的增长空间。

再来看看只购买过一次的客户数量 :

# 统计每个客户第一次和最后一次购买记录
Customer_life = grouped_Customer.Order_Date.agg(['min','max'])
# 查看只有一次购买记录的顾客数量,第一次和最后一次是同一条记录,则说明购买只有一次
(Customer_life['min'] == Customer_life['max']).value_counts()
-----------------------------------------------------
False    1580
True       10
dtype: int64

从结果来看,只购买一次的用户只有10个,大部分用户都会购买多次,说明回头率很高,也验证了上面关于该企业老客户的维系不错的结论。

4.3.3 RFM模型分析

RFM的含义:

  • R(Recency):客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则表示客户交易发生的日期越近。
  • F(Frequency):客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
  • M(Monetary):客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。

RFM分析就是根据客户活跃程度和交易金额的贡献,进行客户价值细分的一种方法。

首先构建RFM表:

rfm = df.pivot_table(index='Customer_ID',
                    values = ["Order_ID","Sales","Order_Date"],
              aggfunc={"Order_ID":"count","Sales":"sum","Order_Date":"max"})

# 所有用户最大的交易日期为标准,求每笔交易的时间间隔即为R
rfm['R'] = (rfm.Order_Date.max() - rfm.Order_Date)/np.timedelta64(1,'D')
# 每个客户的订单数即为F,总销售额即为M
rfm.rename(columns={'Order_ID':'F','Sales':'M'},inplace = True)
rfm.head()

荐
                                                        python数据分析实战之超市零售分析

接着对客户价值进行标注,将客户分为8个等级(2 x 2 x 2):

# 基于平均值做比较,超过均值为1,否则为0
rfm[['R','F','M']].apply(lambda x:x-x.mean())

def rfm_func(x):
    level =x.apply(lambda x:'1'if x>0 else '0')
    level =level.R +level.F +level.M
    d = {
        "111":"重要价值客户",
        "011":"重要保持客户",
        "101":"重要挽留客户",
        "001":"重要发展客户",
        "110":"一般价值客户",
        "010":"一般保持客户",
        "100":"一般挽留客户",
        "000":"一般发展客户"
    }
    result = d[level]
    return result

rfm['label']= rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis =1)
rfm.head()

荐
                                                        python数据分析实战之超市零售分析

对重要价值客户和非重要价值客户进行可视化展示:

rfm.loc[rfm.label=='重要价值客户','color']='g'
rfm.loc[~(rfm.label=='重要价值客户'),'color']='r'
rfm.plot.scatter('F','R',c= rfm.color)

荐
                                                        python数据分析实战之超市零售分析
通过RFM识别不同的客户群体,能够衡量客户价值和客户利润创收能力,可以指定个性化的沟通和营销服务,为更多的营销决策提供有力支持,为企业创造更大的利益。

4.3.4 新用户、活跃用户、不活跃用户和回归用户分析

设置Customer_ID为索引,month为列名,统计每个月的购买次数:

pivoted_counts = df.pivot_table(index= 'Customer_ID',
                               columns= 'month',
                               values= 'Order_Date',
                               aggfunc= 'count').fillna(0)
# 大于一次的全部设为1
df_purchase = pivoted_counts.applymap(lambda x:1 if x>0 else 0)
df_purchase.head()

荐
                                                        python数据分析实战之超市零售分析

定义状态函数并进行状态标记:

def active_status(data):
    status = []
    for i in range(48):
        if data[i] == 0:
            if len(status)>0:
                if status[i-1] == "unreg":
                	# 未注册客户
                    status.append("unreg")
                else:
                	# 不活跃用户
                    status.append("unactive")
            else:
                status.append("unreg")
            
        # 若本月消费了
        else:
            if len(status) == 0:
            	# 新用户
                status.append("new")
            else:
                if status[i-1] == "unactive":
                	# 回归用户
                    status.append("return")
                elif status[i-1] == "unreg":
                    status.append("new")
                else:
                    status.append("active")
    return pd.Series(status)  

purchase_stats = df_purchase.apply(active_status,axis =1)
purchase_stats.head()

荐
                                                        python数据分析实战之超市零售分析

用NaN替代 “unreg”,并统计每月各状态客户数量:

purchase_stats_ct = purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
# 用0填充NaN
purchase_stats_ct.fillna(0).T.plot.area()

荐
                                                        python数据分析实战之超市零售分析

从以上结果可以发现活跃客户、新客户和回归客户,每年呈一定的规律起伏,这可能和年终年末大促有关,需要更多数据进行佐证;同时可以发现新客数量每年均在减少,说明该商家新客获取率较低,如果能在新客户获取上取得突破,会给商家带来很大的增长空间。

4.3.5 复购率和回购率分析
  • 复购率计算指标:用户在该月购买过一次以上算复购。
purchase_r = pivoted_counts.applymap(lambda x :1 if x>1 else np.NaN if x==0 else 0)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(10,4))

荐
                                                        python数据分析实战之超市零售分析

  • 回购率计算指标:在该月购买过,且在下月也购买时计入回购。
def purchase_back(data):
    status=[]
    for i in range(47):
        if data[i] ==1:
            if data[i+1] == 1:
                status.append(1)
            if data[i+1] == 0:
                status.append(0)
        else:
            status.append(np.NaN)
    status.append(np.NaN)
    return status

purchase_b = df_purchase.apply(purchase_back,axis =1,result_type='expand')
(purchase_b.sum()/purchase_b.count()).plot(figsize=(10,4))

荐
                                                        python数据分析实战之超市零售分析

从上可以发现复购率基本大于0.525,且呈总体上升趋势,说明客户忠诚度高,回购率在年中年末呈峰形态,可能与商家折扣活动或节日有关。

5、总结

本文分别通过“场、货、人”三个不同的角度去分析一家全球超市的销售、商品、用户情况,并根据分析结果给出一些有利于拓展用户、提升销量的办法。当然,这份数据集包含信息很多,还可以进行其它一些方面的分析,来给出更好的建议。

本文地址:https://blog.csdn.net/weixin_42384784/article/details/106179705