1 项目介绍
- 项目名称:CD 网用户消费分析
- 使用工具:jupyter notbook
分析步骤及内容:
- 1. 数据预处理——数据的清洗
缺失值的处理、数据类型的转化- 2. 用户消费趋势的分析
从每月的消费总金额、每月的消费次数、每月的产品购买量、每月的消费人数四个维度上进行分析- 3. 用户个体消费数据分析
用直方图,散点图分析累计消费- 4. 用户消费行为分析
首购,用户分层,购买周期等分析
2 项目开始
2.1 数据预处理——清洗
# 导入必备库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
%matplotlib inline #‘%’内置的命令,jupyter专有的定义,比如在pycharm不常用到,inline意思是我做好图之后可以在html页面的单元格进行显示
# 插入数据文件
columns = ['user_id', 'order_dt', 'order_products', 'order_amount']
df = pd.read_table('CDNOW_master.txt', names = columns, sep = "\s+")
注意4点
- 由于是txt文件,所以用方法 read.table 打开
- txt 文件中字段未给出,所以需要传入4个列名以便于分析
- 字段名称分别是 user_id:用户id, order_dt:购买日期,order_products:购买产品数,order_amount:购买金额,一般这四个字段是电商及消费相关的数据的重要指标
- 一般csv文件时以逗号来分隔的,但是此份数据时通过空格来分割的,所以使用参数 '\s+' 处理任意个数的空格
image.png
df['order_dt'] = pd.to_datetime(df.order_dt, format = '%Y%m%d') # Y表示四位数的日期部分,y表示两位数的日期部分
df['month'] = df.order_dt.values.astype('datetime64[M]') # 增加一个 month 字段,转变时间维度便于分析
image.png
image.png
image.png
小结:至此,已完成数据的清洗
2.2 进行用户消费趋势的分析(按月)
- 每月的消费总金额
- 每月消费次数
- 每月产品购买量
- 每月消费人数
2.2.1 每月消费总金额¶
grouped_month = df.groupby('month') # 按月进行聚合数据,形成新的对象
order_month_amount = grouped_month.order_amount.sum() # 求出订货量的总数
order_month_amount.head()
image.png
image.png
2.2.3 每月产品购买量
- 前三个月消费订单量在10000上下,后续平均消费人数则在25000上下波动
grouped_month.order_products.sum().plot() # 每笔订单可能会有多个产品,可求出总产品的销售量
image.png
2.2.4 每月消费人数(需要去重)
-
方法一
image.png
image.png
image.png
2.3 用户个体消费分析
- 用户消费金额和消费次数的描述统计
- 用户消费金额和消费次数的散点图
- 用户消费金额的分布图(二八法则)
- 用户消费次数的分布图
- 用户累计消费金额的占比(百分之多少的用户占了百分之多少的消费额)
2.3.1 用户消费金额和消费次数的描述统计
grouped_user = df.groupby('user_id')
grouped_user.sum().describe()
image.png
2.3.2 用户消费金额和消费次数的散点图和直方图
- 散点图可以揭示某种规律,直方图可以对用户进行分层
grouped_user.sum().query('order_amount < 4000').plot.scatter(x = 'order_amount', y = 'order_products')
image.png
grouped_user.sum().query('order_products < 60').order_products.hist(bins = 40) #
image.png
2.3.3 用户累计消费金额的占比
理解:
- 用户数量和总消费值的比例是随人数上升而不断累加的,所有用户与总消费额的比率是 1
- 所以可以按升序排列出用户数量与总值的比
- 最终可以用 apply 函数遍历cumsum 的累加和算出累加到当前用户数所占总用户的比例
user_cumsum = grouped_user.sum().sort_values('order_amount').cumsum() / 2500315.63 # cumsum 为滚动累加求和
user_cumsum
image.png
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum() / x.sum())
user_cumsum # apply(lambda x:x.cumsum() / x.sum()),除数为占比,被除数为总数
image.png
user_cumsum.reset_index().order_amount.plot() # user_cumsum 其实是一个series,reset_index 会把其转换为数据框,这样便于制图
# order_amount 也可用 order_products 代替,可得出几乎一样的结果
image.png
结论: - 前 2 万用户消费占比 0.4,后5千用户占比 0.6
- 重点维系对象应放在这5千人上
2.4 用户消费行为分析
- 用户第一次消费(首购)
在很多行业里面首购是一个很重要的维度,它和渠道息息相关,尤其是针对客单价比
较高客户留存率比价低的行业,第一次客户从哪里来可以拓展出很多运营方式。
用户最后一次消费 - 新老客消费比
- 多少用户仅消费了一次
- 每月新客占比
- 用户分层
- RFM
- 新、老、活跃、流失
- 用户购买周期(按订单)
- 用户消费周期描述
- 用户消费周期分布
- 用户生命周期(按第一次&最后一次消费)
- 用户生命周期描述
- 用户生命周期分布
2.4.2 新老客户消费比
从两个维度分析
- 多少用户仅消费了一次
- 每月新客占比
user_life = grouped_user.order_dt.agg(['min', 'max']) # 定义用户的购买周期
user_life.head()
image.png
image.png
2.4.3 用户分层
- RFM:立方体模型。分别表示最近一次消费 (Recency)消费频率 (Frequency)消费金额 (Monetary)
- 新、老、活跃、流失
2.4.3.1 RFM
rfm = df.pivot_table(index = 'user_id',
values = ['order_products', 'order_amount', 'order_dt'], # 3 个字段,购买日期,购买金额,购买产品
aggfunc = {'order_dt':'max',
'order_amount':'sum',
'order_products':'sum'}) # 这里所求的是消费产品数,这样可以更加详细的区分
rfm.head()
image.png
rfm['R'] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1, 'D') # 客户最近一次购买日期减去今天(98年6月底)算出时间间距,
# 由于时间类型是日期型,所以要转换为浮点数,除以天数去掉单位
rfm.rename(columns = {'order_products':'F', 'order_amount':'M'},inplace =True) # 统一下字段名
rfm.head()
image.png
rfm[['R','F','M']].apply(lambda x : x - x.mean()).head() # 每个客户在 R F M 三个维度上的值与平均值之差
image.png
def rfm_func(x):
level = x.apply(lambda x:'1' if x >= 1 else '0')
label = level.R + level.F + level.M # 拼接为其中一种组合
d = { # R F M 三个维度可以显示出一个客户的价值,三个维度可以细分为8种组合
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户',
}
result = d[label]
return result
rfm['label'] = rfm[['R','F','M']].apply(lambda x:x - x.mean()).apply(rfm_func, axis = 1)
rfm.head()
image.png
image.png
rfm.loc[rfm.label == '重要价值客户', 'color'] = 'g' # 后来赋予的颜色
rfm.loc[~(rfm.label == '重要价值客户'), 'color'] = 'r' # 后来赋予的颜色
rfm.plot.scatter('F', 'R', c = rfm.color) # 不能直接赋予颜色,必须先赋值
image.png
image.png
2.4.3.2 新、活跃、回流、流失和不活跃用户
1. 可以先用数据透视表查看用户每月购买次数
pivoted_counts = df.pivot_table(index = 'user_id',
columns = 'month',
values = 'order_dt',
aggfunc = 'count').fillna(0) # 没有消费的会用 0 进行填充
pivoted_counts.head()
image.png
2. 简化模型(因为每月用户购买次数并不是重要数据,是否购买才是重点)
image.png
def active_status(data):
status = []
for i in range(18): # 遍历 18 个月的消费情况
# 若本月没有消费
if data[i] == 0: # 判断是否为 0, 0 表示没有消费
if len(status) > 0: # 遍历18个月的情况后,如果其中一个月有消费,则长度大于 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 status
indexs = df['month'].sort_values().astype('str').unique()
pivoted_purchase_status = pivoted_counts.apply(lambda x:pd.Series(active_status(x),index = indexs),axis=1)
image.png
purchase_status_ct = pivoted_purchase_status.replace('unreg',np.NaN).apply(lambda x : pd.value_counts(x))
purchase_status_ct
image.png
image.png
image.png
image.png
2.4.4 用户购买周期
order_diff = grouped_user.apply(lambda x : x.order_dt - x.order_dt.shift()) # shift() 错位函数使数据依次向下移位,第一个值则会变为空值
order_diff.head(10)
image.png
image.png
image.png
image.png
结论:
1. 订单周期呈指数分布
2. 用户的平均购买周期是68天
3. 绝大部分用户的购买周期都低于100天
2.4.5 用户生命周期
image.pngimage.png image.png
2.5 复购率和回购率的分析
- 复购率:自然月内,购买多次的用户占比
-
回购率:曾经购买过的用户咋某一时期内的再次购买占比
image.png
image.png
image.png
image.png
def purchase_back(data): # 定义一个回购函数
status = []
for i in range(17): # 从第一个月开始遍历
if data[i] == 1: # 判断某一个月(从第一个月算起)是否有消费,如果有则分为下面两种情况
if data[i + 1] == 1:
status.append(1) # 判断后一个月是否有消费,如果有则用 1 表示
if data[i + 1] == 0:
status.append(0) # 判断后一个月是否有消费,如果没有则用 0 表示
else:
status.append(np.NaN) # 如果第一个月(前一个月)没有消费则用 NaN 表示
status.append(np.NaN)
return status
indexs = df['month'].sort_values().astype('str').unique()
purchase_b = df_purchase.apply(lambda x : pd.Series(purchase_back(x), index = indexs), axis = 1)
purchase_b.head(5)
image.png
image.png
网友评论