1.项目背景
随着电商的不断发展,网上购物越来越流行,更多电商平台崛起。对于电商卖家来说增加的不止是人们愈来愈高的需求,还要面对更强大的竞争对手。面对这些挑战时,就需要能够及时发现店铺经营中的问题,并且能够有效解决这些实际问题,从而提升自身的竞争力。
根据已有数据对店铺整体运营情况分析,了解运营状况,以及对未来进行预测,已经成为一个电商以及运营等岗位必不可少的技能。
本项目将对一家全球超市4年(2011-2014)的零售数据进行数据分析。
2.分析目标
- 分析每年销售额增长率
- 各个地区分店的销售额
- 销售淡旺季
- 新老客户数
- 利用RFM模型标记用户价值
3.数据理解
数据源于数据科学竞赛平台:Kaggle-https://www.kaggle.com/jr2ngb/superstore-data,
共51290条数据,24个字段。
4.数据清洗
4.1 导入数据
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('white')
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
# 初步判断数据是否有缺失值
import pandas as pd
data= pd.read_csv(r'./superstore_dataset2011-2015.csv',encoding='ISO-8859-1')
data.info()
根据以上结果,对数据进行基本了解,24个字段中有7个字段是数字类型,这7个字段在去计算时不需要转换类型,其它字段都是object类型,在获取数据时注意数据的类型,特别是日期字段的数据,整理数据时将其转换成时间格式,可以方便获取数据。
同时,也发现只有Postal code字段有缺失值,而该字段对分析并不会产生影响,可以不用处理。
4.2 查看缺失值数量
data.isnull().sum()
4.3 查看是否有异常值
data.describe()
describe()函数会对数值型数据,输出结果指标包括count,mean,std,min,max以及第25百分位,中位数(第50位百分位)和第75百分位。通过观察该结果,发现数据及并无异常值存在。
4.4 数据处理
由于很多分析的维度都是建立在时间上的,通过数据类型结果,发现数据中的时间是字符串类型的,所以需要处理时间的类型,将其修改成 datetime类型
data['Order Date'] = pd.to_datetime(data['Order Date'])
data.dtypes
上面将Order Date(订单日期)列的数据类型成功修改成了 datetime 类型,再通过 datetime 可以快速的增加数据的维度,
例如:年、月、季度等
# 通过dt属性返回的对象中可以获取datetime中的年与日等数据
data['Order-year'] = data ['Order Date'].dt.year
data ['Order-month'] = data ['Order Date'].dt.month
data ['quarter'] = data ['Order Date'].dt.to_period('Q')
result = data [['Order Date','Order-year','Order-month', 'quarter']].head()
result.head()
5 具体目标分析
5.1 分析每年销售额的增长率
销售增长率是企业本年销售收入增长额同上年销售收入总额之比。本年销售增长额为本年销售收入减去上年销售收入的差额,它是衡量企业经营状况和市场占有能力、预测企业经营业务拓展趋势的重要指标,也是企业扩张增量资本和存量资本的重要前提,该指标越大,表明其增长速度越快,企业市场前景越好。同样,也可以根据销售额的平均增长率,对下一年的销售额进行预测。
销售额增长率=(本年销售额-上年销售额)/上年销售额*100%
根据当前的数据对该超市2011年-2014年进行销售增长率趋势分析,并给出下一年的销售额建议
# 将数据按年份分组,计算出每年的销售总额
sales_year = data.groupby(by='Order-year')['Sales'].sum()
# 根据销售额增长率公式分别计算出2012年、2013年和2014年的销售额增率
sales_rate_12 = sales_year[2012] / sales_year[2011] -1
sales_rate_13 = sales_year[2013] / sales_year[2012] -1
sales_rate_14 = sales_year[2014] / sales_year[2013] -1
print(sales_rate_12,sales_rate_13,sales_rate_14)
- 用百分数的形式结果,可以用下面的方式将小数改成百分数
sales_rate_12 = "%.2f%%" % (sales_rate_12 * 100)
sales_rate_13 = "%.2f%%" % (sales_rate_13 * 100)
sales_rate_14 = "%.2f%%" % (sales_rate_14 * 100)
print('12年增长率:',sales_rate_12,'\n',
'13年增长率:',sales_rate_13,'\n',
'14年增长率:',sales_rate_14)
- 用图表呈现每一年的销售额和对应的增长率,用表格展示销售额和对应增长率
sales_rate = pd.DataFrame(
{'sales_all':sales_year,
'sales_rate':['0.00%',sales_rate_12,sales_rate_13,sales_rate_14]
})
sales_rate
# 为了更直观的展示数据,可以将数据进行图像展示
## 由于百分比数据不支持绘图,所以重新求占比
sales_rate_12 = sales_year[2012] / sales_year[2011] -1
sales_rate_13 = sales_year[2013] / sales_year[2012] -1
sales_rate_14 = sales_year[2014] / sales_year[2013] -1
sales_rate = pd.DataFrame(
{'sales_all':sales_year,
'sales_rate':[0,sales_rate_12,sales_rate_13,sales_rate_14]
})
sales_rate
# 新建figure对象
fig=plt.figure(figsize=(12,8))
# 新建子图1
ax1=fig.add_subplot(1,1,1)
# ax2与ax1共享X轴
ax2 = ax1.twinx()
ax1.bar(x,y1,width=0.4) # bar的宽度设置
ax2.plot(x,y2,marker='*',color = 'r')
ax1.set_xlabel('年份',fontsize=16)
ax1.set_ylabel('销售额',fontsize=16)
ax2.set_ylabel('增长率',fontsize=16)
ax1.set_title('销售额与增长率',fontsize=20)
ax1.tick_params(axis='both',labelsize=15) # 设置坐标轴字体大小
ax2.tick_params(axis='both',labelsize=15)
plt.grid() # 添加网格线
plt.show()
分析:
结合销售额与增长率 2011 年-2014 年该超市的销售额在稳步上升,说明企业市场占有能力在不断提高,增长率 2012 年-2014 年在增长后趋于平稳,说明企业经营在逐步稳定。同样根据销售和增长率,可以初步制定下一年度的销售额指标是:530万左右,当然具体销售额指标的制定还要再结合公司的整体战略规划。
5.2 各地区分店的销售额
了解该超市的整体销售额情况后,再对不同地区的分店的销售额占比情况进行分析,以便对不同地区分配下一年度的销售额指标,对不同地区分店采取不同的营销策略。
- 首先整体看一下不同地区分店2011-2014年的销售额占比
sales_area = data.groupby(by='Market')['Sales'].sum()
plt.figure(figsize=(7,7))
plt.title('2011年-2014年的总销售额占比',fontsize=20)
sales_area.plot(kind='pie',autopct="%1.1f%%")
plt.show()
分析:
从此图可看出APAC地区销售额占比最大为28.4%.而Canada地区的销售额占比最少,并且只有0.5%。说明市场没有打开,可根据公司的总体战略部署进行取舍,从而根据销售额占比分配下一年的销售额指标。
- 对各地区每一年的销售额进行分析
sales_area = data.groupby(by=['Market','Order-year'])['Sales'].sum()
# 将分组后的多层索引设置成列数据
sales_area = sales_area.reset_index(level=[0,1])
# sales_area = sales_area.reset_index(level=['Market','Order-year'])
# 使用数据透视表重新整理数据
sales_area = pd.pivot_table(sales_area,
index='Market',
columns='Order-year',
values='Sales')
# 绘制图形
sales_area.plot(kind='bar',
title='2011年-2014年不同地区销售额对比',
figsize=(10,6)
)
plt.title('2011年-2014年不同地区销售额对比',fontsize=20)
plt.xlabel('Market',fontsize=16)
plt.tick_params(labelsize=14) # 设置坐标轴字体大小
plt.xticks(rotation=45) # 设置x轴文字转向
plt.show()
分析:
从上图可以看出,各个地区2011-2014年销售总额均呈增长的趋势,在APAC地区和EU地区的增长速度较快,可以看出市场占有能力也在不断增加,企业前景较好,下一年可适当加大运营成本,其他地区可根据自身地区销售特点,吸取上面两个地区的运营模式。
- 不同类型产品在不同地区的销售额占比
category_sales_area=data.groupby(by=['Market','Category'])['Sales'].sum()
# 将分组后的多层索引设置成列数据
category_sales_area=category_sales_area.reset_index(level=['Market','Category'])
# 使用数据透视表重新整体数据
category_sales_area=pd.pivot_table(category_sales_area,
index='Market',
columns='Category',
values='Sales')
# 绘制图形
category_sales_area.plot(kind='bar',
title='不同类型产品在不同地区的销售额对比',
figsize=(10,6)
)
plt.title('不同类型产品在不同地区的销售额对比',fontsize=20)
plt.xlabel('Market',fontsize=16)
plt.tick_params(labelsize=14) # 设置坐标轴字体大小
plt.xticks(rotation=45) # 设置x轴文字转向
plt.legend(fontsize='x-large',loc='upper center')
plt.show()
分析:
所有产品按照三个大的类型进行了区分,分别是Furniture,Technology,OfficeSupplies。
通过上图大致可以看出,在各大地区销售额都比较高是电子产品,可根据企业的整体战略部署适当的加大对各地区该品类的投入,以便扩大优势。
5.3 销售淡旺季分析
根据超市的整体销售额情况和不同类型产品在不同地区的销售情况,再对每年每月的销售额进行分析,根据不同月份的销售情况,找出重点销售月份,从而制定经营策略与业绩月度及季度指标拆分。
为了方便观察数据,需要将数据根据年和月进行分组,并计算出每年每月的销售总额,再将其制作成年、月,销售额的数据透视表
year_month = data.groupby(by=['Order-year','Order-month'])['Sales'].sum()
# 将索引订单年转为一列数据
sales_year_month = year_month.reset_index(level=[0,1])
# 利用透视表的确定销售额预览表
sales_year_month = pd.pivot_table(sales_year_month,
index='Order-month',
columns='Order-year',
values='Sales')
# 绘制图形
sales_year_month.plot(title='每年每月的销售总额',figsize=(10,6))
plt.xlabel('Order-month',fontsize=16)
plt.tick_params(labelsize=14) # 设置坐标轴字体大小
plt.show()
分析:
通过图表可看出,该超市2011-2014年每一年的销售额同比上一年都呈上升趋势,所以很容易发现该超市的旺季是下半年,另外在上半年销售额中发现6月份的销售额也是较高的,所以可以在6月份开始加大一些运营成本,进而更大一步提高销售额,但需要注意下半年的7月份和10月份销售额会有明显的下降,可针对这些下降的月份多举行一些营销活动。
5.4 新老客户数
企业的老用户一般都是企业的忠诚用户,有相对较高的粘度,也是为网站带来价值的主要用户群体;而新用户则意味着企业业务的发展,是企业价值不断提升的前提。可以说“老客户是企业生存的基础,新用户是企业发展的动力”,企业的发展战略往往是在基于保留老用户的基础上不断地提升新用户。
所以分析新老用户的意义在于:
- 通过分析老用户,来确定企业的基础是否稳固,是否存在被淘汰的危机;
- 通过分析新用户,来衡量企业的发展是否顺利,是否有更大的扩展空间。
# 根据Customer ID列数据进行重复值的删除,保证数据集中所有的客户ID都是唯一的
data = data.drop_duplicates(subset=['Customer ID'])
# 根据Order-year','Order-month'两个字段进行分组,并使用size()函数对每个分组进行计数
new_consumer = data.groupby(by=['Order-year','Order-month']).size()
# 为方便使用透视表对数据进行整理,需要先将索引转化成数据列
new_consumer = new_consumer.reset_index(level=[0,1])
# 使用数据透视表功能,将年份作为数据的列索引,月份作为数据的行索引
sales_year_month = pd.pivot_table(new_consumer,
index='Order-month',
columns='Order-year',
values=0)
# 绘制图形
sales_year_month.plot(title='每年每月新增用户数',figsize=(10,6))
plt.xlabel('Order-month',fontsize=16)
plt.tick_params(labelsize=14) # 设置坐标轴字体大小
plt.title('每年每月新增用户数',fontsize=20)
plt.legend(fontsize='x-large')
plt.show()
分析:
根据图表可以看出,从2011年开始到2014年,每一年的新增用户呈逐年减少的趋势,可看出该网站对保持老用户是有效的,网站的运营状况较为稳定。但是,新客户获取率较低,可以不定期进行主动推广营销,从而增加新客户数。
5.5用户价值RFM模型分析
目前几乎所有企业业务都是以客户的需求为主导,客户至上都希望服务好客户,促进销售转化,最好能对产品和品牌产生粘性,长期购买。于是企业都会绞尽脑汁的做活动、上新品、蹭热点、做营销,不断地拓展客户和回访维系客户感情。但是,这些工作除了运气好以外,大部分效果都是不好的,真正有价值的用户没有几个。不同阶段、不同类型的用户需求点不同,有的用户图便宜,有的用户看新品,有的注重服务,粗狂式的营销运营方法,最后的结果往往都是事与愿违。使企业的资源利润无法发挥其最大效用去创造最大化的利润。
那么如何进行客户价值分析,甄选出有价值的客户,让企业精力集中在这些客户上,有效的提升企业竞争力使企业获得更大的发展。解决的方法即用户精细化运营,通过各类运营手段提高不同类型的用户在产品中的活跃度、留存率和付费率。
而如何将用户从一个整体拆分成特征明显的群体决定了运营的成败。在用户价值领域,最具影响力并得到实验验证的理论与模型有:用户终生价值理论、用户价值金字塔模型,策论评估矩阵分析法和RFM客户价值分析模型等。
RFM的含义:
- R(Recency):客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,
反之则表示客户交易发生的日期越近。 - F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃
- M(Monetary):客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,
反之则表示客户价值越低。
RFM模型是衡量用户价值和用户创利能力的经典工具,依托于用户最近一次购买时间、消费频次以及消费金额。在应用RFM模型时,要有用户最基础的交易数据,至少包含用户 ID,交易金额,交易时间三个字段。
- 根据R,F,M这三个维度,可以将客户分为以下 8 种类型
探索该超市2014年的客户群体
5.5.1 第一步,分析的数据是该超市2014年全年的数据,取出2014年的数据
# 获取2014年数据
data_14 = data [data ['Order-year']==2014]
# 用这三列数据就可以制定rfm
data_14 = data_14[['Customer ID','Order Date','Sales']]
data_14.head()
5.5.2 第二步,对2014年数据按照Customer ID进行分组,计算每个用户的最后购买时间
# 确定统计日期
data_14['Order Date'].max()
# Timestamp('2014-12-31 00:00:00')
# 每个用户的最后购买时间
recency_df = data_14.groupby(['Customer ID'],as_index=False)['Order Date']. \
agg({'last_purchase_date':'max'})
recency_df.head()
5.5.3 第三步,计算RFM模型中的R(最近一次交易时间的间隔),F(购买次数)和M(销售额总数)值
import datetime as dt
now = dt.datetime(2014,12,31)
# 每个用户消费最近一次交易时间的间隔
recency_df['Recency'] = recency_df['last_purchase_date'].apply(lambda x :
(now - x).days)
# 每个用户消费次数
frequency_df = data_14.groupby('Customer ID',as_index=False)['Customer ID'].agg({'Frequency':'count'})
# 每个用户消费的金额
monetary_df = data_14.groupby('Customer ID',as_index=False)['Sales'].agg({'Monetary':'sum'})
5.5.4 第四步,合并各表
rfm_df = pd.merge(recency_df, frequency_df, on='Customer ID')
rfm_df = pd.merge(rfm_df, monetary_df, on='Customer ID')
rfm_df.sample(5)
5.5.5 第五步,根据经验及业务场景设定分值的给予区间,进行评分
# 添加r_score评分列
rfm_df['r_score'] = pd.qcut(rfm_df['Recency'],
bins = [0, 0.25, 0.5, 0.75, 1],
labels=[4, 3, 2, 1])
rfm_df['r_score'] = rfm_df['r_score'].astype('int')
# 添加f_score评分列
rfm_df['f_score'] = pd.cut(rfm_df['Frequency'],
bins=[0,10,20,30,50],
labels=[1, 2, 3, 4],
duplicates='drop').astype('int')
# 添加m_score评分列
rfm_df['m_score'] = pd.cut(rfm_df['Monetary'],
bins=[0, 0.25, 0.5, 0.75, 1],
labels=[1, 2, 3, 4]).astype('int')
rfm_df.head()
5.5.6 第六步,根据每一个维度计算出对应的平均分
对数据的R、F、M进行高低维度的划分,也就是当评分值大于等于对应的平均值是表示高,
同理当评分值小于对应的平均值时是表示低。
rfm_df['r_cate'] = rfm_df['r_score'] > rfm_df['r_score'].mean()
rfm_df['f_cate'] = rfm_df['f_score'] > rfm_df['f_score'].mean()
rfm_df['m_cate'] = rfm_df['m_score'] > rfm_df['m_score'].mean()
rfm_df['r_cate'] = rfm_df['r_cate'].astype('int')
rfm_df['f_cate'] = rfm_df['f_cate'].astype('int')
rfm_df['m_cate'] = rfm_df['m_cate'].astype('int')
rfm_df.sample(10)
5.5.7 第七步,根据RFM的高低值对每个用户进行类型标记
def f(a, b, c):
return [a, b, c]
rfm_df['rfm_list'] = rfm_df.apply(lambda x: f(x['r_cate'], x['f_cate'], x['m_cate']),
axis=1)
def rmf(x):
if x == [1, 1, 1]:
return '重要价值客户'
elif x == [1, 0, 1]:
return '重要发展客户'
elif x == [0, 1, 1]:
return '重要保持客户'
elif x == [0, 0, 1]:
return '重要挽留客户'
elif x == [1, 1, 0]:
return '一般价值客户'
elif x == [1, 0, 0]:
return '一般发展客户'
elif x == [0, 1, 0]:
return '一般保持客户'
elif x == [0, 0, 0]:
return '一般挽留客户'
rfm_df['custom'] = rfm_df['rfm_list'].apply(rmf)
rfm_df.head()
5.5.8 第八步,可视化
rmf_group_df = rfm_df.groupby('custom', as_index=False)['Customer ID']\
.agg({'custom_num':'count'})
x = rmf_group_df['custom'].values
y = rmf_group_df['custom_num'].values
plt.figure(figsize=(20,8))
plt.style.use('ggplot') # 图风格
plt.title("RFM模型分布", size=24) # 图标题
plt.xticks(size=16) # x轴字体大小调整
plt.yticks(size=16) # y轴字体大小调整
sns.barplot(x, y, palette="summer")
plt.show()
6 结论
1.结论依据:
不论在什么环境中,总会有二八法则的存在。例如:20%的客户为公司提供了 80%的利润。根据前面RMF模型分类出8种客户的不同性质,下面是根据用户对平台的贡献度做了排序:
一般挽留客户→一般发展客户→一般保持客户→一般价值客户→重要挽留客户→重要 发展客户→重要保持客户→重要价值客户
下面分析一下每组客户的特性:
【 一般挽留客户】:这类客户RFM三个值都低,说明已经是流失的客户。针对这批客户召回的成本一般会比较高,因为用户长时间没在平台有任何行为,有可能 app 都已经卸载。所以一般针对这种客户只会在特定的大型活动才采取全面的短信、广告、推送召回。比如在双十一、黑色星期五等大型购物狂欢节。或者说公司到了一个新阶段大量资金投入用户新增, 比如看到过的“瓜分 5 个亿”、“无上限砍价”等活动。
【 一般发展客户】:这类客户只是有近期购买行为但是购买商品利润低而且也不活跃。一般分两种类型,一种是刚注册的客户,另一种就是由于体验感一般接近流失边缘的客户。针对 刚注册的用户一般会采取“新人大礼包”等优惠,一般“新人大礼包”会尽量多的覆盖平台上的不同商品品类,提高新客户了解平台产品的动力。而针对接近流失的客户应该从客服、物流等多角度追溯客户过去的不满原因,对平台进一步完善。
【一般保持客户】:这类客户只是频繁浏览,但是很久没有成交了。针对这类用户,一般会结合最近浏览的商品进行相关优惠推送。促进用户的成交行为。
【一般价值客户】:这类客户属于已经在平台上养成了自己的购买习惯,已经处于多次频繁购买的阶段,但是购买的商品价格都比较低,产生的利润也就低。对这类客户应该进一步分析属于购买力低还是大额商品有其他习惯成交的平台。针对前者一般不需要采取特别的措施,而 针对后者应该时刻注意用户的浏览商品动向,如果浏览远超过平时客单价的商品应该及时给予优惠政策。
【重要挽留客户】:这类消费金额较高,消费频次偏低,而且已经很久没有消费行为了。这种客户曾经算是平台的忠实用户,而且能为平台提供比较大的利润。但是很有可能马上就要流失了,所以应该进行重点挽留,如给用户更多关怀,应当主动客服沟通,建立平台形象, 针对用户有什么不满意的地方应当及时解决,并给予优惠补偿。
【重要发展客户】:这类用户最近有消费,且整体消费金额高,但是购买不频繁。这种客户是有购买力的客户,应当重点维护,提升用户在消费中的体验感,比如加送“运费险”等等附 加增值服务。
【 重要保持客户】:最近一次消费时间较远,消费金额和消费频次比较高。这种客户一般是有网购习惯,但是最近却很久没有来消费。说明很可能已经流向别的平台。所以非常有潜力可挖,必须重点发展。要关注竞品的活动,做对比出合理方案。
【重要价值客户】:这类客户 RFM三个值都很高。是平台重点维护的客户,保证服务质量,保持客户在平台每次购物体验。
2.本次案例结论
通过对不同客户的行为分析,结合案例的结果。从统计结果中看,该平台重要价值客户占总体 17.54%,说明该公司已经沉淀了一批优良客户,而且这个比例还算是比较乐观。但有 28.86%的重要保持客户,这批客户是曾高频购买且消费金额大的客户,但是这批客户近期没有成交行为说明已经有流失倾向,这批客户需要着重关注。另外一般发展用户也占了 27.33% 的比例,说明在用户新增的阶段做的还不错,但是其他类型的比例都偏少。
这组数据说明了 这个平台整体已经处于客户流失的阶段,用户整体活跃行为已经降低,需要维护现有忠诚客户的同时,也要花精力在新用户往重要价值客户的转化上。