背景:
该项目是某国外CD网站的消费数据,通过分析该网站的消费情况,通过对消费情况分布,从用户消费价值等数据进行分析,为平台创造更多利润,合理辨别广告投放人群,对平台商品销售数据进行分析,根据复购率、回购率、高价值用户等标签,从而进行有针对性的客情管理。数据集来源网上CD国外网站,不包含隐私信息,从数据网站获取。
数据字段:
user_id:用户ID
order_id:订单日期
order_products:购买产品数
order_amount:购买金额
数据清洗:
1、导入数据集并查看数据类型:
通过pandas导入数据集,源数据缺少列标签需要添加列标签,用\s+表示匹配任意空白符,并查看前5行数据
数据导入:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']
names = ["user_id","order_dt","order_products","order_amount"]
df = pd.read_table("CDNOW_master.txt",sep = "\s+",names = names)
df.info()
df.head()
2、为了后期数据分析需要对主要是针对异常值\缺失值的处理, 此份数据主要两方面:时间转化为标准格式、缺失值处理。
df.isnull().sum()
df["order_date"] = pd.to_datetime(df.order_dt,format = "%Y%m%d")
df["month"] = df.order_date.values.astype("datetime64[M]")
df.head()
通过描述统计判断数据分布情况,存在极大值干扰,可在后面处理根据切比雪夫定理排除极值干扰
df.describe()
- 大部分订单只消费了少量商品(平均2.4),有一定极值干扰(最大值99)
- 用户消费金额比较稳定,平均消费35元,有一定极值干扰(最大值1286)
消费分析
一、根据时间维度划分,查看网站整体的消费水平
group_month = df.groupby('month')
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes0,axes1 = axes.flatten()
# 每月销售金额
group_month.order_amount.agg('sum').plot(ax=axes0)
axes0.set_title('每月消费金额')
axes0.set_ylabel('消费金额')
# 每月销售产品数
group_month.order_products.sum().plot(c="g",ax=axes1)
axes1.set_title('每月销售产品数')
axes1.set_ylabel('销售产品数')
由图表可知:在网站的消费金额和销售产品数在前3个月较高,并且在3月达到峰值,但是从4月份开始就呈现断崖式下跌(可以初步判断出前三个月应该是网站新上线大/大促吸引大量用户涌入,因为没有具体业务场景就不做展开分析)
group_month = df.groupby('month')
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes2,axes3 = axes.flatten()
# 每月订单数
group_month.order_products.count().plot(c="y",ax=axes2)
axes2.set_title('每月订单数')
axes2.set_ylabel('订单数')
#每月客户数
group_month.user_id.apply(lambda x :len(x.drop_duplicates())).plot(c="r",ax=axes3) #客户去重:lambda x :drop_duplicates()
axes3.set_title('每月客户数')
axes3.set_ylabel('客户数')
由图表可知:订单数和客户数同消费金额可产品数变化趋势一致,均在前三个月较高,4月开始下滑,变化趋势一致也是符合常识规律的。4月断崖式的流失需要马上查询出现问题原因,因为缺少相关业务场景就不做具体描述(一般可从数据质量、网站bug、产品质量、竞对情况等分析原因)
注意:每月客户数处理时,因为一个客户可以在某月多次下单,所以需要去重处理
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes0,axes1 = axes.flatten()
# 每月客单价
group_month_pice = group_month.order_amount.sum()/group_month.user_id.unique().apply(lambda x:len(x))
group_month_pice.plot(ax=axes0)
axes0.set_title('每月客单价')
axes0.set_ylabel('客单价')
# 每月件单价
group_month_up = group_month.order_amount.sum()/group_month.order_products.sum()
group_month_up.plot(ax=axes1,c="y")
axes1.set_title('每月件单价')
axes1.set_ylabel('件单价')
二、根据用户维度划分:查看用户消费水平
group_user = df.groupby('user_id')
group_user_des = group_user[['order_amount','order_products','order_dt',]].agg({"order_amount":"sum",
"order_products":"sum",
"order_dt":"count"}).describe()
group_user_des.rename(columns = {'order_dt':'消费次数','order_amount':'消费总金额','order_products':'产品购买数(件)'})
2、用户的消费情况分布
fig,axes = plt.subplots(1,3,figsize=(16,4))
axes0,axes1,axes2 = axes.flatten()
# 用户消费金额的分布情况
group_user.sum().query('order_amount<1200').order_amount.plot.hist(bins=20,ax=axes0)
axes0.set_title('用户消费金额的分布情况')
axes0.set_xlabel('消费金额')
axes0.set_ylabel('人数')
# 用户消费次数的分布情况
group_user.sum().query('order_products<100').order_products.plot.hist(bins=20,color="g",ax=axes1)
axes1.set_title('用户消费次数的分布情况')
axes1.set_xlabel('消费次数')
axes1.set_ylabel('人数')
# 用户购买产品数量的分布情况
group_user.count().query('order_dt<20').order_dt.plot.hist(bins=20,color="y",ax=axes2)
axes2.set_title('用户购买产品数量的分布情况')
axes2.set_xlabel('购买产品数量')
axes2.set_ylabel('人数')
3、用户消费金额与购买产品数量散点图:查看消费金额和购买数量的关系
#用户消费金额与购买产品数量散点图
group_user.sum().query("order_amount<4000").plot.scatter(x="order_amount",y="order_products",title="'用户消费金额与产品购买数量")
group_user_cum = group_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
group_user_cum.reset_index().order_amount.plot(figsize=(6,4))
plt.title('用户消费金额占比')
plt.xlabel('用户数量')
plt.ylabel('消费金额占比')
图片可知:用户个体的消费数据来看,基本符合二八法则,少部分高价值用户贡献了大部分的业绩,针对高价值用户进行维护,对于新用户转化成高价值用户,形成良好的用户分成结构体系
三、用户消费行为:
通过前面按时间和用户的维度分析数据,了解了网站的基本情况,现需通过用户的数据对用户的消费行为进行进一步细化分析,通过数据指标、RFM等模型、生命周期等对用户进行分层分析,为后续的用户运营提供数据支撑
1、用户的首购和最后一次消费时间分布
#用户消费行为
group_user = df.groupby('user_id')
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes0,axes1 = axes.flatten()
#用户首购时间
group_user.min().order_date.value_counts().plot(ax=axes0)
axes0.set_title("用户首购时间")
axes0.set_ylabel("人数")
#用户最后一次消费时间
group_user.max().order_date.value_counts().plot(ax=axes1)
axes1.set_title("用户最后一次消费时间")
axes1.set_ylabel("人数")
df.groupby('user_id')
2、以时间为划分,如果最后一次消费时间等于第一次消费时间,则就是只消费一次的,反之消费多次
user_life = df.groupby('user_id').order_date.agg(["max","min"])
user_life.head()
3、新老用户的占比
(user_life["min"] == user_life["max"]).value_counts()
group_user_lifecycle = group_user.order_date.apply(lambda x:x.max()-x.min())/np.timedelta64(1,'D')
# 用户生命周期为0天的用户占比
lifecycle_new = len(group_user_lifecycle[group_user_lifecycle==0])/len(df.user_id.unique())
lifecycle_num = len(group_user_lifecycle[group_user_lifecycle>0])/len(df.user_id.unique())
values = [lifecycle_new,lifecycle_num]
label = ['用户仅消费一次','用户消费多次']
fig = plt.figure(figsize=(8,8))
plt.pie(values,labels=label,autopct='%1.1f%%')
plt.title('用户消费次数占比')
plt.show()
4、用户分层:
RFM模型是网点衡量当前用户价值和客户潜在价值的重要工具和手段
1、通过数据透视,得到用户的消费金额、最近一次消费时间、消费购买产品数。
rfm = df.pivot_table(index = "user_id",
values = ["order_amount","order_products","order_date"],
aggfunc = {"order_amount":"sum",
"order_products":"sum",
"order_date":"max"})
rfm.head()
2、为了方便查询,对数据进行重命名管理
购买产品数重新命名为f,消费金额重新命名为m,r为用户最近一次消费的时间距目前(数据取最大值)的时间间隔
rfm['R']=(df.order_date.max() - group_user.order_date.max()) / np.timedelta64(1,"D") #去除时间单位
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
rfm=rfm[['R',"F",'M']]
rfm.head()
3、RFM用户分层:通过与平均值的差来判断每个指标的水平。如:m,如果与平均值差值小于0,则该用户总消费小于平均水平,消费金额贡献小将客户分
标签:重要价值(距离上一次消费时间近、购买次数多、消费金额高)、重要保持、重要挽留、重要发展、一般价值、一般发展、一般维持、一般挽留
rfm[["R","F","M"]].apply(lambda x:x-x.mean())
def level_label(x):
level = x.apply(lambda x:'1' if x> 0 else '0')
model = level.R+level.F+level.M
dic = {
"111":"重要价值客户",
'101':'重要发展客户',
"011":"重要维护客户",
'001':'重要挽留客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'100':'一般发展客户',
'010':'一般维持客户',
'000':'一般挽留客户'}
return dic[model]
rfm['label'] = rfm.apply(lambda x:x-x.mean()).apply(level_label,axis=1)
rfm.groupby("label").sum() #按照RFM模型划分,各层次消费金额
rfm.groupby("label").count() #按照RFM模型划分,各层次有多少人
按照RFM模型划分,查看到各类标签用户人数分布,一般发展用户人数占比最高
fig,axes = plt.subplots(1,3,figsize=(14,4))
axes0,axes1,axes2 = axes.flatten()
rfm_per=rfm.groupby('label').M.agg(['count','sum']).apply(lambda x :x/x.sum())
rfm_per['avg']=rfm_per['sum'] / rfm_per['count']
rfm_per['count'].plot.bar(ax=axes0)
axes0.set_title('用户分层人数占比')
axes0.set_xlabel('人数占比')
rfm_per['sum'].plot.bar(ax=axes1)
axes1.set_title('用户分层消费金额占比')
axes1.set_xlabel('消费金额占比')
rfm_per['avg'].plot.bar(ax=axes2)
axes2.set_title('用户分层平均消费金额')
axes2.set_xlabel('平均消费金额')
从图表可知,接近60%的用户属于一般发展客户,但是仅仅贡献消费金额不到20%,平均消费金额仅仅0.25万美元,在各类客户当中平均消费金额属于最低水平;第二大用户群是重要维护客户,人数占比接近20%,贡献的销售额达到63%左右,平均消费金额达3.3万元,这一类客户价值极高,对于这这一类用户重点维护。
4、用户的复购和回购率
复购率:自然月内,用户多次购买占比(当月多次购买)
回购率:曾经购买的用户在某一时间内再次回购占比
pivot_user=df.pivot_table(index='user_id',
columns='month',
values='order_amount',
aggfunc='count').fillna(0)
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes0,axes1=axes.flatten()
fig,axes = plt.subplots(1,2,figsize=(12,4))
axes0,axes1=axes.flatten()
# 用户每月复购率
repeated_purchase = pivot_user.applymap(lambda x:1 if x>1 else np.NaN if x==0 else 0)
repeated_purchase.apply(lambda x:x.sum()/x.count()).plot(ax=axes0)
axes0.set_title('每月复购率')
axes0.set_ylabel('复购率')
# 用户每月回购率
def buy_back_choose(x):
mask = x>0
label = []
for i in range(len(x)-1):
if mask[i] and mask[i+1]:
label.append(1)
elif mask[i]:
label.append(0)
else:
label.append(np.NaN)
return pd.Series(label,index = x.index[:-1]) #index[:-1]去掉最后一列,因为6月首次购买的话就不存在回购
buy_back = pivot_user.apply(buy_back_choose,axis=1)
buy_back.apply(lambda x:x.sum()/x.count()).plot(ax=axes1)
axes1.set_title('每月回购率')
axes1.set_ylabel('回购率')
前三个月用户基本为新用户的首购,复购率和回购率较低属于正常
四月之后复购率在20%上下波动,回购率25% - 35%波动(波动大小需要看贴合业务场景判读这个数据是否在正常范围波动,因没有想过的标杆数据对比,因此不能判断出这个数据是否正常)
总结:
通过对网站消费数据的获取导入、数据处理与探索,从用户和时间维度的划分,对网站的经营情况进行了了解。在前3个月网站新用户大量涌入,消费总金额和产品购买数都达到最高值,在4月后呈下跌,但是回购率和复购率开始呈上升趋势(是否在正常范围波动需要结合业务场景)。消费总金额也符合28原则,少部分用户贡献了大部分业绩,对于少部分用户购买了大金额产品可能会拉升平均值,需要结合分位数进行判断。根据对用户消费行为、用户生命周期、用户标签的划分,可有效地进行精细化的运营到达提升业绩目的