用户消费行为分析(python)

目录

数据读取:

数据处理:

数据分析:

用户整体消费分析

用户个体消费分析

用户分组进行消费描述性统计

直方图观察消费分布情况

用户累计消费金额占比分析(贡献度)

用户消费行为

首购时间

最后一次购买时间

用户分层

新老用户分析

用户购买周期

用户生命周期

用户复购率

用户回购率

总结


数据集:Bruce Hardie: Datasets

分析框架:

数据读取:

import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt 
from datetime import datetime 
%matplotlib inline
#绘图风格,选用的是R语言绘图库风格
plt.style.use('ggplot')
# user_id:用户ID,order_dt:购买日期,order_products:购买产品数量,order_amount:购买金额
data = pd.read_table('CDNOW_master.txt',sep='\s+',header=None,names=['user_id','order_dt','order_products','order_amount'])
data.head(10)
data.describe()

可以从数据中看出,存在同一个用户多次购买该产品记录,同时日期格式存在问题,需要手动转换

进行数据描述后,可以看出购买产品数量最小为1,但是购买金额最小却是0,可能数据集存在问题或者刷单/免费赠送情况。同时,绝大部分订单的购买产品数量都不大,多为1-3之间,存在大客户(购买99个产品)。绝大部分订单消费金额在10-50之间。

可以看出,数据集一共近七万条,且没有缺失值。时间类型需要把Int转换。

数据处理:

#转换数据类型
data['order_date'] = pd.to_datetime(data['order_dt'],format='%Y%m%d')
#format按照指定格式
#%Y:1994  %m:两位月份   %d两位日数  %y:两位年份94   %h:两位小时   %M:两位分钟   %s:两位秒
#datetime64[M] 表示将日期数据转换为“年月”格式,即只保留年份和月份,而忽略具体的日期。
data['month'] = data['order_date'].astype('datetime64[M]') #[M]:控制转换后精度
data.head()

增加一列仅精确到月份的,便于后续针对月用户活动数据进行分析。

数据分析:

用户整体消费分析
#按月份统计产品购买数量,消费金额,次数,人数
#消费趋势分析

plt.figure(figsize=(20,15),dpi=100)
#每月产品购买数量
plt.subplot(221) #两行两列占据第一个位置
data.groupby(by='month')['order_products'].sum().plot() #默认折线图
plt.title('每月产品购买数量')

#每月消费金额
plt.subplot(222) #两行两列占据第一个位置
data.groupby(by='month')['order_amount'].sum().plot() #默认折线图
plt.title('每月产品售出金额')

#每月消费次数
plt.subplot(223) #两行两列占据第一个位置
data.groupby(by='month')['user_id'].count().plot() #默认折线图
plt.title('每月用户消费次数')

#每月消费人数
plt.subplot(224) #两行两列占据第一个位置
data.groupby(by='month')['user_id'].apply(lambda x:len(x.drop_duplicates())).plot() #默认折线图
plt.title('每月消费人数')

我们可以从图上一和图二看出产品售出呈现下降趋势

1997年1-3月销量高,后面销量下降并保持稳定,说明用户粘性不足;

需要结合业务分析原因(例如春节前后影响,公司销售策略影响,政策影响等)

从图三图四可以看出,二月份消费人数增多时,消费次数却减少,有可能出现大订单。

前三个月的消费订单数在10000笔左右,后续月份的平均消费订单数则在2500笔;

前三个月每月的消费人数在8000-10000之间,后续月份平均消费人数在2000人。

用户个体消费分析
用户分组进行消费描述性统计
user_group = data.groupby(by='user_id').sum()
print(user_group.describe())
print('用户数量:',len(user_group))

可以观察到,消费人数共有23570名用户购买该CD。

消费数量平均购买7个CD,但是中位数为3,且最大值为1033,表现为右偏分布。

消费金额平均为106,中位数为43,且存在消费高的用户,平均数与75%分位数相近,属于右偏分布。

dui

可以看出,用户消费金额与购买量呈线性关系,斜率为CD单价,约15左右

极值点较少,可忽略不计,对样本影响不大。

直方图观察消费分布情况
#绘制直方图,观察消费分布情况
plt.figure(figsize=(10,3),dpi=100)

plt.subplot(121)
plt.xlabel('每个订单消费金额')
#bins:区间分数,影响柱子宽度。宽度=(最大值-最小值)/bins
data['order_amount'].plot(kind='hist',bins=60)

plt.subplot(122)
plt.xlabel('每个uid购买数量')
data.groupby(by='user_id')['order_products'].sum().plot(kind='hist',bins=60)

可以看出,订单消费金额大部分在100以内,单个用户购买数量较小,为50以内。

用户画像主要为消费金额低,购买小于50个产品的用户人数占大多数,这在电商行业较为普遍。

用户累计消费金额占比分析(贡献度)
#用户分组,汇总消费金额,排序,重置索引
user_cumsum = data.groupby(by='user_id')['order_amount'].sum().sort_values().reset_index()
user_cumsum

#用户消费金额累加,累加函数 cumsum
#这样算贡献率为要算的用户范围直接除以最后一行的总和就好了
user_cumsum['amount_cumsum'] = user_cumsum['order_amount'].cumsum()
user_cumsum.tail()

amount_total = user_cumsum['amount_cumsum'].max()#消费总额
#计算贡献度
#axis=0 或 'index':对每一列应用函数(默认)。axis=1 或 'columns':对每一行应用函数。
user_cumsum['prop'] = user_cumsum.apply(lambda x:x['amount_cumsum']/amount_total,axis=1)
user_cumsum.tail()

prop列表示的是截止到该用户,所购买产品金额的贡献度

user_cumsum['prop'].plot()
plt.xlabel('用户数量')
plt.ylabel('贡献度')

我们可以看到,两万名用户贡献了百分之四十的销量,三千多名用户贡献了百分之六十的销量。这也体现了二八法则。

用户消费行为
首购时间

用户分组,选择最早购买时间,计算一天有多少新用户

data.groupby(by='user_id')['order_date'].min().value_counts().plot()

从图中可以看出,新用户的变化从1.1-2.1呈现明显递增趋势,说明公司可能有价格的变化和促销活动的开展,而2.1后新用户增加总体呈现递减趋势。

最后一次购买时间
data.groupby(by='user_id')['order_date'].max().value_counts().plot()

大多数用户最后购买时间集中在前三个月,,说明缺少忠诚用户。1997年5月用户最后购买次数急剧减少,说明很多用户在此时 停止复购,CD 公司的客户保持率较低。

用户分层

透视表:可动态直观显示汇总结果。(pivot_table)(报表神器)

#透视表(index:相当于group分组,values指取出的列,aggfunc指对于列的处理方法,聚合函数必须有效)
rfm = data.pivot_table(index='user_id',
                      values=['order_products','order_amount','order_date'],
                      aggfunc={
                          'order_date':'max',#最后一次购买时间
                          'order_products':'sum',#购买数量总和
                          'order_amount':'sum'#消费总金额
                      })
rfm.head()

#最近一次消费离现在时间差,转换精度,精确到天(保留一位小数)
rfm['R'] = (rfm['order_date'].max() - rfm['order_date'])/np.timedelta64(1,'D')
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
rfm.head()

RFM计算:每一列数据减去数据所在列平均值,有正有负,结果与1比较,结果>=1,设置为1,否则为0,把每条记录转换为特定代码(例:110,001,010,100……)

#定义函数,转为字符串
def rfm_func(x):
    level = x.apply(lambda x:'1' if x>=1 else '0' )
    label = level['R'] + level['F'] + level['M']#字符串拼接
    d = {
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要发展客户',
        '001':'重要挽留客户',
        '010':'一般保持客户',
        '000':'一般挽留客户',
        '110':'一般价值客户',
        '100':'一般发展客户'
    }
    result = d[label]
    return result

#每一列数据减去数据所在列平均值
rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.head()

#客户分层可视化
for label,grouped in rfm.groupby(by='label'):
    print(label,grouped)
    x = grouped['F']
    y = grouped['R']
    plt.scatter(x,y,label = label)
plt.legend() #显示图例
plt.xlabel('Frequency')
plt.ylabel('Recenttime')

从图中可以看出,R较小,F、M较大,这是公司喜欢的用户,表示产品售卖的不错。

新老用户分析

首先进行用户分层处理,用透视表的形式

#用户分层数据
pivoted_counts = data.pivot_table(
                index='user_id',
                columns='month',#视表的列将基于 month 列的值。
                values='order_dt',
                aggfunc='count'
).fillna(0)#将没有消费记录补为0
pivoted_counts

浮点数不好观察,把他转换为1和0

df_purchase = pivoted_counts.applymap(lambda x:'1' if x>0 else 0)
#apply:作用于用户dataframe数据中的一行或一列数据
#applymap:作用于dataframe数据的每一个元素
#map:series函数,在dataframe中无法使用map函数,其作用于series中每个元素
df_purchase.head()

判断新老用户,活跃用户,回流用户

def active_status(data):#data为整行数据,共18列
    status = []#存储18个月的状态:unreg\new\active\unactive\return
    for i in range(18):
        #本月无消费
        if data[i] == 0:
            if len(status) == 0:#前面无记录(97年1月)
                status.append('unreg')
            else:#判断上个月状态
                if status[i-1] == 'unreg':
                    status.append('unreg')
                else:
                    status.append('unactive')#无论上个月是否消费过,本月无消费,均为不活跃
                    
            pass       
        #本月有消费
        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,df_purchase.columns)#值为status,列名为df_purchase的列名,pd.series指对行进行操作
                

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

#分析各类用户占比情况,用NaN空值替换unreg(没必要分析)
purchase_states_ct = purchase_states.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_states_ct.head()

可视化:

#数据可视化,把空值补为0
#将数据进行转置
purchase_states_ct.T.fillna(0).plot.area()
#面积图是一种展示数据随时间变化的图表,通常用于显示数量的变化和组成部分的比例。

可以看出,新用户在1-4月大量注册,并较为活跃,4月后趋于稳定;

4月之后,回流用户较为稳定,是网站重点客户。

#用户占比(例:return/该月总消费人数)
rate = purchase_states_ct.T.fillna(0).apply(lambda x: x/x.sum(),axis=1)
plt.plot(rate['return'],label='return')
plt.plot(rate['active'],label='active')
#plt.plot(rate['unactive'],label='unactive')
plt.legend()

从图中可以看出,从2月开始,回流用户逐渐增加,到六月份开始逐步保持稳定,平均维持在5%的比例;

活跃用户从1-2月增加趋势较大(猜测活动营销吸引新用户),4月开始极速下降至5月,随后趋于平稳下降趋势,平均占比2.5%左右。

用户购买周期

相邻两次购买产品的时间间隔

#shift函数:可把数据移动到指定位置(整体向左\右\上下移一行\列)
#计算购买周期(购买日期时间差)
order_diff = data.groupby(by='user_id').apply(lambda x: x['order_date']-x['order_date'].shift())#当前订单日期-上次订单日期
order_diff.describe()

可视化:

#数据可视化周期
(order_diff/np.timedelta64(1,'D')).hist(bins=15)

从图中可以看出,平均消费周期为68天,大部分用户消费周期少于100天;

图像呈现长尾分布,大部分用户消费周期较短,少部分为不积极用户;针对消费频率低的用户,运营部门可以在这批用户消费3天后进行电话回访,或赠送优惠券等活动,增大消费频率。

用户生命周期

第一次消费与最后一次消费的差值

#agg函数:以对数据进行汇总操作,例如计算均值、总和、最大值、最小值等。
user_life = data.groupby(by='user_id')['order_date'].agg(['min','max'])
(user_life['max']==user_life['min']).value_counts().plot.pie(autopct='%1.1f%%')#仅消费一次,保留一位小数
plt.legend(['仅消费一次','多次消费'])
plt.title('用户消费比例')

从图中看出,一半以上用户仅消费一次,说明运营情况存在问题,留存率较差,用户粘性低。

#生命周期
(user_life['max']-user_life['min']).describe()

可以看出,四分位数一直到75%才为294天,可知大部分用户只购买一次产品;

75%分位数之后的用户为核心用户,需要重点维持。

绘制所有用户生命周期直方图和多次购买产品的用户直方图

plt.figure(figsize=(12,6))
plt.subplot(121)
((user_life['max']-user_life['min'])/np.timedelta64(1,'D')).hist(bins=15)
plt.title('用户生命周期')
plt.xlabel('天数')
plt.ylabel('用户人数')

plt.subplot(122)
u_1 = (user_life['max']-user_life['min']).reset_index()[0]/np.timedelta64(1,'D')#加索引取天数列,转换为天数数值类型
u_1[u_1>0].hist(bins=15)
plt.title('多消费用户生命周期')
plt.xlabel('天数')
plt.ylabel('用户人数')

从图中可以看出,在多次消费用户的群体中,生命周期小于100天的可以归结为普通用户,忠诚度低;生命周期大于300天的用户作为忠诚用户,需重点维护。

用户复购率

每个月用户购买次数>1为复购用户

复购率为复购用户/普通消费用户(购买次数=1)

因此,将用户本月购买次数为0的设置为NaN(以免干扰count计数)

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() 消费总人数(无NaN)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(12,6))

从图中可以看出,复购率从一至四月上涨率较快,然后趋于平稳,维持在20%-22%。

用户回购率
def purchase_back(data):
    status = []#存储用户回购率状态
    #1:回购用户  0:非回购用户(当前月消费,下月未消费) NaN:(当前月下月均未消费)
    for i in range(17):
        #当前月份消费
        if data[i] == 1:
            if data[i+1] == 1:
                status.append(1)
            elif data[i+1] == 0:
                status.append(0)
        else:
            status.append(np.NaN)
    status.append(np.NaN)#填充最后一列数据
    return pd.Series(status,df_purchase.columns)

purchase_b = df_purchase.apply(purchase_back,axis=1)
purchase_b.head()

(purchase_b.sum()/purchase_b.count()).plot(label='回购率')

从图中可以看出,复购率低于回购率,前三个月逐渐上升,后面趋于稳定。

总结

该项目主要针对用户消费行为进行分析,分别从整体趋势,个体特征,消费额,消费周期等方面进行拆分。主要运用到以下方法:

1.针对用户按照月份提取进行整体个体分析,分析维度为人数,消费金额和购买量;

2.消费分析:首购时间,最后一次购买时间,相邻两个购物时间间隔,用户分层(RFM+数据透视表pivoted),分析维度为新、活跃、不活跃用户流失分析,回流用户分析;

3.复购率和回购率分析。

注:此文章为学习笔记记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值