数据分析——如何分析用户消费行为

本篇文章主要以Numpy,Pandas,matplotlib为主,来实现在工作中如何进行用户消费行为分析。技术本身不是重点,重要的是体会数据分析背后的思想。特总结如下,希望能帮助大家。

分析步骤.png

数据获取

链接:https://pan.baidu.com/s/1kl0CYSunhbRHXv1vQ69WrA
提取码:l9ed

字段含义:
user_id:用户ID
order_dt:购买日期
order_products:购买产品数
order_amount:购买金额

一、数据清洗

import pandas as pd
import numpy as np
from sqlalchemy import create_engine
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
# 从mysql中 读取数据
def reader(sql):
    engine=create_engine('mysql+pymysql://root:123456@localhost:3306/test?charset=utf8')
    df = pd.read_sql(sql,engine)
    return df
df = reader("SELECT user_id,order_dt,order_products,order_amount from datas")
df.info()
image.png

数据集没有空值,数据还算正常

df.head()
image.png

订单时间需要处理一下

df['order_dt'] = df['order_dt'].apply(lambda x: pd.to_datetime(x).strftime('%Y-%m-%d'))
# 因为后续要按月、日统计,所以将时间字段切分
def DateSplit(df, col):
    temp_df = df[col].str.split('-',expand=True)
    temp_df.columns = ["year","month","day"]
    df = pd.concat([df,temp_df],axis=1)
    #df = df.drop("order_dt",axis=1)
    return df

data = DateSplit(df,col='order_dt')
data
image.png
df.describe()
image.png

由上可知:

1.用户每个订单平均消费了2.4个产品,大部分订单集中在小额

  1. 用户的消费金额比较稳定,平均消费在35.8元,中位数在25.9元,有一定的极值干扰。

二、用户消费趋势分析(按月)

  • 1、每月消费的总金额
grouped_month = data.groupby('month')
order_grouped_month = grouped_month.order_amount.sum()
order_grouped_month.head()
order_grouped_month.plot()
image.png

由上图可知,消费金额在1月份到3月呈上升趋势,3月份达到最高峰,后期销量趋于平稳,每月在1万左右波动

  • 2、每月的消费次数
grouped_month.user_id.count().plot()
image.png

分析:前三个月平均消费订单在1万左右,后续月份趋于平稳,约在2500单每月

  • 3、每月的消费人数
grouped_month.user_id.apply(lambda x:len(x.drop_duplicates())).plot()
image.png

分析:每个月的消费人数小于每月的消费次数,但是区别不大。前3个月月均消费人数在9000左右,后续月均2000不到,一样是前期消费人多,后期平稳的趋势。

# 透视表 每月消费金额  每月消费次数,每月消费产品数
data.pivot_table(index='month',
               values=['user_id','order_amount','order_products'],
              aggfunc={'user_id':'count','order_amount':'sum','order_products':'sum'})

# 每人每月消费次数
grouped_month.user_id.apply(lambda x:x.value_counts())
# 每月人均消费金额
grouped_month.price.sum()/grouped_month.user_id.apply(lambda x:len(x.drop_duplicates()))
# 每月人均消费次数
 grouped_month.user_id.count()/grouped_month.user_id.apply(lambda x:len(x.drop_duplicates()))
# 每月人均消费产品数
 grouped_month.order_products.sum()/grouped_month.user_id.apply(lambda x:len(x.drop_duplicates()))

三、用户个体消费分析

  • 用户消费金额,消费次数的描述统计
user = data.groupby('user_id')
user.sum().describe()
image.png

分析:

  1. 每位用户平均购买7件商品,最多的用户买了1033件。
  2. 用户平均消费额(客单价)100元,标准差是240,结合分位数和最大值看,平均值和75分位接近。
结论:肯定存在小部分高额消费用户,小部分的用户占了消费的大头,符合二八法则。
  • 用户消费金额,消费次数的散点图
user1 = user.sum().reset_index()
user2 = user.count()['year'].reset_index()
users = user1.merge(right=user2,how='inner',on='user_id')
users.plot.scatter(x='order_amount',y='year')
image.png

分析:
  通过绘制用户的散点图,用户比较健康而且规律性很强。销售数据呈线性,离群点少。

  • 用户消费金额的分布图
users.query('order_amount<1000').order_amount.plot.hist(bins = 20)
image.png

分析:
从直方图可知,大部分用户的消费能力确实不高,绝大部分集中在很低的消费档次。高消费用户在图上几乎看不到。

  • 用户消费次数的分布图
users.query('order_products < 100')['order_products'].plot(kind='hist',bins=40)
image.png
  • 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
# pd.to_numeric(x) 将字符串转为浮点
user_cumsum = user1.sort_values('order_amount').apply(lambda x:pd.to_numeric(x).cumsum()/2500315.63)
user_cumsum.reset_index().order_amount.plot()
image.png

分析:
按用户消费金额进行升序排序,由图可知50%的用户仅贡献了15%的销售额。而排名前5000的用户就贡献了60%的消费额

也就是说,只要维护好这5000个客户,就可以完成业绩KPI的60%,如果能把5000个用户运营的更好就可以占比70%-80%甚至更高。

四、用户消费行为

image.png
用户第一次购买
data.groupby('user_id').min().month.value_counts()
image.png

可见用户第一次消费集中在一月份
查看用户总数

data['user_id'].unique().size
结果:23570
用户最后一次购买
data.groupby('user_id').max().month.value_counts()
image.png
data.groupby('user_id').max().month.value_counts().plot()
image.png

大部分最后一次购买集中在1、2月份,说明很多用户购买了一次后就不再进行购买
随着时间的递增,最后一次购买数在逐渐递减,消费呈现流失上升的趋势,用户忠诚度在慢慢下降。

新老用户消费比(多少用户只消费了一次,每月新客占比)
user_comsume = data.groupby('user_id').order_dt.agg(['min','max'])
user_comsume
image.png
(user_life['min'] == user_life['max']).value_counts()
image.png

分析可见:只消费过一次的用户占了总数的二分之一

用户分层(RFM,活跃回流等)
RFM模型

最近一次消费 (Recency)
消费频率 (Frequency)
消费金额 (Monetary)

RFM 将要使用数据透视表

# order_products--求消费产品总数、order_amount---求消费总金额、order_dt--求最近一次消费时间
datas = data.pivot_table(index='user_id',
               values=['order_amount','order_products','order_dt'],
              aggfunc={'order_amount':'sum','order_products':'sum','order_dt':'max'})
datas
image.png
import time
today = time.strftime("%Y-%m-%d", time.localtime())

datas['R'] =  - (pd.to_datetime(datas['order_dt'])-pd.to_datetime(today))/np.timedelta64(1,'D')
datas.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
datas
image.png
# 根据RFM值给用户打标签
def user_actives_status(x):
    level = x.apply(lambda x: '1' if x > 0 else '0')
    lable = level.R+level.F +level.M
    d ={'111':'重要价值客户','011':'重要保持客户','101':'重要挽留客户','001':'重要发展客户','110':'一般价值客户','010':'一般保持客户','100':'一般挽留客户','000':'一般发展客户',
    }
    result = d[lable]
    return result
datas['label'] = datas[['R','F','M']].apply(lambda x:x-x.mean()).apply(user_actives_status,axis=1)
datas
image.png
datas.groupby('label').sum()
image.png

分析:M表示不同层次客户累计消费金额,重要保持客户最高

# 各等级用户数
datas.groupby('label').count()
image.png

分析:不同层次用户的消费人数,之前重要保持客户的累计消费金额最高,这里人数排第2,但与一般挽留用户人数差距比较大

# 给不同层次客户用颜色区分设置
datas.loc[datas.label=='重要价值客户','color'] = 'g'
datas.loc[~(datas.label=='重要价值客户'),'color'] = 'b'
datas.plot.scatter('F','R',c=datas.color)
image.png

分析:

  1. 从RFM分层可知,大部分用户为重要保持客户,但是这是由于极值的影响,所以RFM的划分应该尽量以业务为准。
    尽量用小部分的用户覆盖大部分的额度,不能为了数据好看划分等级。

  2. RFM是人工使用象限法把数据划分为几个立方体,立方体对应相应的标签,我们可以把标签运用到业务层面上。
    比如重要保持客户贡献金额最多159203.62,我们如何与业务方配合把数据提高或者维护;而重要发展客户和重要挽留客户他们有一段时间没消费了,我们如何把他们拉回来。

新、活跃、回流、流失
#用户每月消费次数
user_counts = data.pivot_table(index='user_id',columns='month',values='order_dt',aggfunc='count').fillna(0)
user_counts.head()
image.png
purchase = user_counts.applymap(lambda x:1 if x> 0 else 0)
purchase
image.png
def actives_status(data):
    status = []
    for i in range(12):
        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] == 'unreg':
                    status.append('new')
                elif status[i-1] == 'unactive':
                    status.append('return')      
                else:
                    status.append('active')
    return pd.Series(status, index = purchase.columns)
  • 若本月没有消费:
    若之前未注册,本月还是未注册
    若之前有消费,则是回流/不活跃
  • 若本月有消费:
    若第一次消费,则是新用户
    若上个月是未注册,则是新用户
    若上个月是不活跃,则本月是回流
    除此之外,是活跃
ddd = purchase.apply(actives_status,axis=1)
ddd
image.png

每月不同活跃用户的计数

purchase_status = ddd.apply(lambda x:pd.value_counts(x))
purchase_status
image.png

每月不同活跃用户占比
消费用户构成:活跃 + 新增 + 回流

purchase_status.fillna(0).T
purchase_status.fillna(0).T.plot.area()
image.png
purchase_status.T.apply(lambda x: x/x.sum(),axis=1)
image.png

分析报告:
由上表可以看到每月用户的消费状态变化。

    1. 活跃用户,持续消费用户对应的是---消费运营质量;
    1. 回流用户(上月不消费本月消费)对应的是---唤回运营情况;
    1. 不活跃的用户对应的是---用户流失情况。
  • 分析结果:流失用户增加,回流用户正在减少。
用户购买周期(按订单)
# 将用户分组后,每个用户的订单购买时间进行错位相减  shift():下一行减上一行的值
order_diff = data.groupby('user_id').apply(lambda x:pd.to_datetime(x.order_dt) - pd.to_datetime(x.order_dt).shift())
order_diff.head(10)
image.png

分析:

  1. 可以看到:user_id 1为空值,说明用户只购买过一个订单

  2. user_id 2 的用户第一笔订单与第二笔订单在同一天购买

order_diff.describe()
(order_diff/np.timedelta64(1,'D')).hist(bins=10)
image.png

分析:
订单周期呈指数分布,用户的平均购买周期是68天,绝大部分用户的购买周期都低于100天。

用户生命周期(第一笔订单时间 & 最后一笔订单时间)
(pd.to_datetime(user_comsume['max'])-pd.to_datetime(user_comsume['min'])).describe()
image.png
# 用户生命周期大于0天的分布图
u = ((pd.to_datetime(user_comsume['max'])-pd.to_datetime(user_comsume['min'])).reset_index()[0] /np.timedelta64(1,'D'))
u[u>0].hist(bins=40)
image.png

分析:

  1. 有不少用户生命周期靠拢在0天,部分质量差的用户虽然消费了两次,但是仍然无法持续,
    用户首次消费30天以内应该尽量引导;

  2. 少部分用户集中在50-300天,属于普通型的生命周期;

  3. 高质量用户的生命周期,集中在400天以后,这属于忠诚用户

复购率和回购率的分析

复购率:自然月内,购买多次的用户占比

回购率:曾经购买过的用户在某一时期内的再次购买占比

# # applymap()针对DataFrame里的所有数据。使用lambda函数,因为设计了多个结果,所以要用两个if else
purchase_r = user_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
image.png
复购率
(purchase_r.sum()/purchase_r.count()).plot()
image.png

分析:

  1. 用sum和count相除即可计算出复购率。这两个函数都会忽略掉NaN,而NaN是没有消费的用户,count不论是0或1都会统计,所以是总的消费用户数。而sum求和计算了消费两次及以上的用户。这里比较巧妙的用了替代法计算复购率。sql中也可以用。

  2. 图上可以看出复购率在早期,因为大量新用户加入的关系,新客的复购率并不高,而在后期,这时的用户都是大浪淘沙剩下的老客户,复购率比较稳定,在20%左右.

回购率:回购率是某一个时间窗口内消费的用户,在下个时间窗口仍旧消费的占比。
# 消费金额进行透视

pivoted_amount = data.pivot_table(index='user_id',
                                columns='month',
                                values='order_amount',
                                aggfunc='mean')
pivoted_amount.fillna(0,inplace=True)
columns_month = data['month'].sort_values().astype('str').unique()
pivoted_amount.columns = columns_month

pivoted_amount.head()
image.png
pivoted_purchase = pivoted_amount.applymap(lambda x : 1 if x>0 else 0)
pivoted_purchase.head()
image.png
# 0代表当月消费过次月没有消费过,1代表当月消费过次月依然消费

def purchase_return(data):
    status = []
    for i in range(11):
        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 pd.Series(status, index = pivoted_purchase.columns)

pivoted_purchase_return = pivoted_purchase.apply(purchase_return,axis = 1)

pivoted_purchase_return.head()
image.png
(pivoted_purchase_return.sum()/pivoted_purchase_return.count()).plot()
image.png

分析:

  1. 从上图看出,用户的回购率高于复购率,约在30%左右,和老客户差异不大。

  2. 从回购率和复购率综合分析,新客的整体质量低于老客,老客的忠诚度(回购率)很好,消费频次稍次

完毕~

你可能感兴趣的:(数据分析——如何分析用户消费行为)