用户消费行为分析报告

用户消费行为分析报告

一、项目背景:

该项目对购买某网站电子产品的用户消费数据进行分析(2020年1月至2020年11月),研究用户的基本属性、消费特征、价值度与活跃度、复购率和回购率情况,为提升销售额以及营销的精准度提供一些思路。

二、数据来源:

https://www.kesci.com/mw/dataset/601e971ab233440015800bc7/file

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] =False #显示符号
from PIL import Image
from IPython.display import display

# 读取PNG图片
image = Image.open('字段解释.png')

# 获取当前图片大小
width, height = image.size
# 设置图片尺寸
new_width = int(width * 0.5)  # 调整为原来宽度的0.5
new_height = int(height * 0.5)  # 调整为原来高度的0.5

# 调整图片尺寸
resized_image = image.resize((new_width, new_height))

# 显示调整后的图片
display(resized_image)

在这里插入图片描述

三、分析框架

image = Image.open('用户消费行为分析.png')

width, height = image.size
new_width = int(width * 0.5)  # 调整为原来宽度的0.5
new_height = int(height * 0.5)  # 调整为原来高度的0.5
resized_image = image.resize((new_width, new_height))

display(resized_image)

在这里插入图片描述

四、结论先行

1.整体趋势:2020年1至4月份销售额和订单量较少且稳定,4月份开始至8月份持续增长,9-11月份虽有下降但也处于比1-4月份高的水平,可能与五一小长假、暑假、开学季和国庆小长假有关;

2.用户属性:
1)30-35岁和40-45岁的男性数量以及45-50岁的女性数量较突出→多向这类用户进行推送,促活;
2)15-20岁、40-45岁、45-50岁这三个年龄段的用户消费金额较高→多推送一些高价位商品;
3)广东、上海、北京的销售额、订单数和消费人数均遥遥领先,同时虽然湖南消费人数较少,但订单数和销售额均排第四,很有潜力→这4个城市可加大营销力度;
4)品牌销量TOP3:samsung、apple、ava,产品类别销量TOP3:智能手机、笔记本、冰箱,可将这些商品作为主推产品,进行引流;且对于销量好的产品,需重点关注库存情况,避免缺货;对于销量差的产品,需及时进行清仓处理;

3.用户整体消费特征:
1)五一小长假、暑假、开学季、十一小长假的销售额、订单量都不错,尤其是8月份的销售额全年最高,对于这些关键节点,需提前准备好各类资源,运营计划、库存、物流、客服资源等;
2)大部分用户会在13-20时下单,以及周末的订单量较高,对于这些时间节点,需保障好网站的运行稳定性;

4.用户个人消费特征:
1)消费次数和消费金额高度相关,因此可通过提高消费次数,来提高消费金额;
2)共93804位用户,14.7%的用户贡献了将近60%的销售额,需对这部分用户重点维护,制定对应的营销方案;

5.用户消费周期
1)用户购买周期均值为9.6天,小部分用户购买周期在50天以上,对于这部分用户可在其消费后9天左右通过赠送优惠券等方式来刺激召回;
2)用户生命周期均值为32天,可在用户消费后第30天左右对其进行引导,促使其再次消费,延长生命周期;75%分位数的用户生命周期为42天,生命周期>42天的用户属于核心用户,需根据其特点推出针对性的营销活动,引导其持续消费;

6.用户价值度分析
通过RFM模型分析,发现一般发展用户数量最多,其次是重要保持用户和一般挽留用户;
针对重要价值用户,需重点维护,提供VIP服务,给予专享权益、定期福利等活动;
针对重要发展用户,消费频次较低,需要提升他们的活跃度,不断优化产品和服务,制定对应策略来提升他们的购买频率;
针对重要保持用户,应主动与用户保持联系,可通过定期邮件/短信推送,与用户保持联系与互动;
针对重要挽留用户,需重点防止流失,可主动联系用户调查具体原因,想办法挽回;
针对一般价值用户,可通过发放不同形式优惠券,引导用户多次消费,增加消费金额;
针对一般发展用户,这类用户可能属于新用户,可提供新手福利,并在各种节假日活动时及时提醒;
针对一般保持用户,这类用户是预流失用户,前期活跃过,后期发现产品、服务、奖励等无法满足预期需求,不再复购,需对其做好利益和情感的触达;
针对一般挽留用户,这类用户可能已流失一段时间,不易挽回,在预算有限的情况下,暂且考虑放弃。

五、数据清洗

删除无用列、转换数据类型、修改并增加时间相关列、删除重复值、缺失值处理和异常值处理;

#数据读入
df = pd.read_csv(r'C:\Users\13779\Desktop\电子产品销售分析.csv')
df.head()
Unnamed: 0event_timeorder_idproduct_idcategory_idcategory_codebrandpriceuser_idagesexlocal
002020-04-24 11:50:39 UTC229435993205453698615159662235090899062.268105e+18electronics.tabletsamsung162.011.515916e+1824.0海南
112020-04-24 11:50:39 UTC229435993205453698615159662235090899062.268105e+18electronics.tabletsamsung162.011.515916e+1824.0海南
222020-04-24 14:37:43 UTC229444402405808622022739483190571836582.268105e+18electronics.audio.headphonehuawei77.521.515916e+1838.0北京
332020-04-24 14:37:43 UTC229444402405808622022739483190571836582.268105e+18electronics.audio.headphonehuawei77.521.515916e+1838.0北京
442020-04-24 19:16:21 UTC229458426315407423622739483168174244392.268105e+18NaNkarcher217.571.515916e+1832.0广东
df.info()
#数据量:564169,原始字段:12
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 564169 entries, 0 to 564168
Data columns (total 12 columns):
 #   Column         Non-Null Count   Dtype  
---  ------         --------------   -----  
 0   Unnamed: 0     564169 non-null  int64  
 1   event_time     564169 non-null  object 
 2   order_id       564169 non-null  int64  
 3   product_id     564169 non-null  int64  
 4   category_id    564169 non-null  float64
 5   category_code  434799 non-null  object 
 6   brand          536945 non-null  object 
 7   price          564169 non-null  float64
 8   user_id        564169 non-null  float64
 9   age            564169 non-null  float64
 10  sex            564169 non-null  object 
 11  local          564169 non-null  object 
dtypes: float64(4), int64(3), object(5)
memory usage: 51.7+ MB
#1.删除无用的Unnamed: 0列
del df['Unnamed: 0']
#2.转换数据类型(否则以科学计数法的形式展示)
df['order_id'] = df['order_id'].astype(object)
df['product_id'] = df['product_id'].astype(object)
df['category_id'] = df['category_id'].astype(object)
df['user_id'] = df['user_id'].astype(object)
df['age'] = df['age'].astype(int)
df.head()
event_timeorder_idproduct_idcategory_idcategory_codebrandpriceuser_idagesexlocal
02020-04-24 11:50:39 UTC229435993205453698615159662235090899062268105426648171520.0electronics.tabletsamsung162.011515915625441993984.024海南
12020-04-24 11:50:39 UTC229435993205453698615159662235090899062268105426648171520.0electronics.tabletsamsung162.011515915625441993984.024海南
22020-04-24 14:37:43 UTC229444402405808622022739483190571836582268105430162997248.0electronics.audio.headphonehuawei77.521515915625447879424.038北京
32020-04-24 14:37:43 UTC229444402405808622022739483190571836582268105430162997248.0electronics.audio.headphonehuawei77.521515915625447879424.038北京
42020-04-24 19:16:21 UTC229458426315407423622739483168174244392268105471367840000.0NaNkarcher217.571515915625443148032.032广东
#2.转换数据类型(经上述处理,category_id和user_id保留了一位小数,利用apply和round函数进一步调整)
df['category_id'] = df['category_id'].astype(object).apply(lambda x: round(x))
df['user_id'] = df['user_id'].astype(object).apply(lambda x: round(x))
df.head()
event_timeorder_idproduct_idcategory_idcategory_codebrandpriceuser_idagesexlocal
02020-04-24 11:50:39 UTC229435993205453698615159662235090899062268105426648171520electronics.tabletsamsung162.01151591562544199398424海南
12020-04-24 11:50:39 UTC229435993205453698615159662235090899062268105426648171520electronics.tabletsamsung162.01151591562544199398424海南
22020-04-24 14:37:43 UTC229444402405808622022739483190571836582268105430162997248electronics.audio.headphonehuawei77.52151591562544787942438北京
32020-04-24 14:37:43 UTC229444402405808622022739483190571836582268105430162997248electronics.audio.headphonehuawei77.52151591562544787942438北京
42020-04-24 19:16:21 UTC229458426315407423622739483168174244392268105471367840000NaNkarcher217.57151591562544314803232广东
#3.修改并增加时间相关列(将UTC时间修改为北京时间)
from datetime import datetime, timedelta
df['event_time'] = df['event_time'].apply(lambda x:str(x)[:20])
df['event_time'] = pd.to_datetime(df['event_time']) + timedelta(hours=8)
#3.修改并增加时间相关列(增加month/day/hour/dayofweek列)4
df['date'] = df['event_time'].dt.date
df['month'] = df['event_time'].dt.month
df['day'] = df['event_time'].dt.day
df['hour'] = df['event_time'].dt.hour
df['dayofweek'] = df['event_time'].dt.day_name()
df.head()
event_timeorder_idproduct_idcategory_idcategory_codebrandpriceuser_idagesexlocaldatemonthdayhourdayofweek
02020-04-24 19:50:39229435993205453698615159662235090899062268105426648171520electronics.tabletsamsung162.01151591562544199398424海南2020-04-2442419Friday
12020-04-24 19:50:39229435993205453698615159662235090899062268105426648171520electronics.tabletsamsung162.01151591562544199398424海南2020-04-2442419Friday
22020-04-24 22:37:43229444402405808622022739483190571836582268105430162997248electronics.audio.headphonehuawei77.52151591562544787942438北京2020-04-2442422Friday
32020-04-24 22:37:43229444402405808622022739483190571836582268105430162997248electronics.audio.headphonehuawei77.52151591562544787942438北京2020-04-2442422Friday
42020-04-25 03:16:21229458426315407423622739483168174244392268105471367840000NaNkarcher217.57151591562544314803232广东2020-04-254253Saturday
#4.检查并删除重复值
df.duplicated().sum()
df.drop_duplicates(inplace=True)
#共有674条重复记录
#5.缺失值处理
df.isnull().sum()
event_time            0
order_id              0
product_id            0
category_id           0
category_code    129221
brand             27184
price                 0
user_id               0
age                   0
sex                   0
local                 0
date                  0
month                 0
day                   0
hour                  0
dayofweek             0
dtype: int64
#5.缺失值处理(category_code存在129370个缺失值,brand存在27224个缺失值,但这些数据的缺失并不影响分析,用’others’填充)
df['category_code'].fillna('others',inplace=True)
df['brand'].fillna('others',inplace=True)
df.isnull().sum()
event_time       0
order_id         0
product_id       0
category_id      0
category_code    0
brand            0
price            0
user_id          0
age              0
sex              0
local            0
date             0
month            0
day              0
hour             0
dayofweek        0
dtype: int64
#6.异常值处理(price为0)
(df['price'] == 0).sum()
#共存在39行price为0的数据,剔除这部分数据
df = df[df['price'] > 0]
#6.异常值处理(年份为1970年的数据)
df['event_time'].min()
df = df[df['event_time'].dt.year != 1970]
#重置索引
df = df.reset_index().drop('index', axis=1)
#处理后的数据预览
df.head()
event_timeorder_idproduct_idcategory_idcategory_codebrandpriceuser_idagesexlocaldatemonthdayhourdayofweek
02020-04-24 19:50:39229435993205453698615159662235090899062268105426648171520electronics.tabletsamsung162.01151591562544199398424海南2020-04-2442419Friday
12020-04-24 22:37:43229444402405808622022739483190571836582268105430162997248electronics.audio.headphonehuawei77.52151591562544787942438北京2020-04-2442422Friday
22020-04-25 03:16:21229458426315407423622739483168174244392268105471367840000otherskarcher217.57151591562544314803232广东2020-04-254253Saturday
32020-04-26 16:45:57229571652144961955915159662235092616972268105442636858112furniture.kitchen.tablemaestro39.33151591562545038284820重庆2020-04-2642616Sunday
42020-04-26 17:33:47229574059474970222915159662235091048922268105428166508800electronics.smartphoneapple1387.01151591562544876646421北京2020-04-2642617Sunday

六、用户属性分析

# 1.性别分析
df.groupby('sex')['user_id'].nunique().plot(kind='pie', autopct='%.1f%%')
plt.title('性别分布')
# 男性与女性买家比例接近1:1

在这里插入图片描述

#性别&消费金额分析
order_amount = df.groupby('user_id')['price'].sum().to_frame().rename(columns={'price':'amount'})
sex = df.loc[:,['user_id','sex']].set_index('user_id')
duplicate_rows = sex.index.duplicated()
sex = sex[~duplicate_rows]
sex_amount = pd.merge(order_amount, sex, left_index=True, right_index=True)
sex_amount.groupby('sex')['amount'].describe()

#对比男性与女性的消费金额,发现各区段的消费金额都差不多,最大值男性稍高些;
countmeanstdmin25%50%75%max
sex
46790.01248.5610094136.9864340.02141.180462.461148.0475160426.63
47014.01250.5181694250.3460410.02147.855453.101152.7225165439.03
# 2.年龄分析
age_range = df.loc[:,['user_id','age']]
age_range.drop_duplicates(inplace=True)
pd.cut(age_range['age'],bins=[15,20,25,30,35,40,45,50]).value_counts().sort_index().plot(kind='bar')
plt.title('年龄分布')

plt.show()
#各年龄段的用户数量差距不大,40-45年龄段的用户数量稍多些,45-50年龄段的用户最少;

在这里插入图片描述

#性别&年龄组合分析
df['age_range'] = pd.cut(df['age'],bins=[15,20,25,30,35,40,45,50],
                         labels=['15-20','20-25','25-30', '30-35', '35-40', '40-45', '45-50'])
data = df.groupby('age_range')['sex'].value_counts().unstack().plot()

#对比男性与女性的不同年龄段的消费人数,发现30-45岁男性的人数多于女性,45-50岁的女性数量明显高于男性数量;
#图中出现了3个高峰,分别30-35岁男性数量、40-45岁男性数量以及45-50岁的女性数量,可以多向这类用户推送商品信息;

在这里插入图片描述

#年龄&消费金额分析
age_range = df.loc[:,['user_id','age_range']].set_index('user_id')
duplicate_rows = age_range.index.duplicated()
age_range = age_range[~duplicate_rows]
age_amount = pd.merge(order_amount, age_range, left_index=True, right_index=True)
age_amount.groupby('age_range')['amount'].describe()

#通过对不同年龄段的消费金额进行分析,发现15-20岁、40-45岁、45-50岁年龄段的用户消费金额较高,可多向这类户进行推送;
countmeanstdmin25%50%75%max
age_range
15-2013326.01233.0607424318.2377390.02148.1000462.4601148.0400153588.55
20-2513501.01248.6419034190.3487460.02140.9200460.5501152.3500160426.63
25-3013448.01255.9618404328.0352900.02145.7900457.6851148.0875130853.08
30-3513411.01303.6890294630.9968690.02143.4250443.2201145.6900165439.03
35-4013409.01140.1556693281.4724550.02138.8700453.1901145.8600119062.38
40-4513552.01278.5479514224.4241470.02145.0825462.4601144.0300117885.33
45-5013157.01287.0085474259.0888140.02150.4400462.9201163.9500136738.03
# 3.地域分析--消费人数&订单数&销售额

#不同省份消费人数
fig,ax = plt.subplots(1, 3, figsize=(14, 8))
df.groupby('local')['user_id'].nunique().sort_values(ascending=True).plot(kind='barh',ax=ax[0])
ax[0].set_xlabel('消费人数')
ax[0].set_ylabel('省份')

#不同省份订单数量
df.groupby('local')['order_id'].nunique().sort_values(ascending=True).plot(kind='barh',ax=ax[1])
ax[1].set_xlabel('订单数')
ax[1].set_ylabel('省份')

#不同省份成交金额
df.groupby('local')['price'].sum().sort_values(ascending=True).plot(kind='barh',ax=ax[2])
ax[2].set_xlabel('销售额')
ax[2].set_ylabel('省份')

fig.suptitle('地域分布', fontsize=16, fontweight='bold')
plt.subplots_adjust(wspace=0.5)
plt.show()

# 广东、上海、北京的消费人数、订单数以及销售额均遥遥领先,此外虽然湖南消费人数最少,但订单数和销售额均排在第四,很有潜力;

在这里插入图片描述

#按喜好品牌分析
brand = df.groupby('brand')['user_id'].count().sort_values(ascending=False).head(20)
brand.plot(kind='bar')
plt.xlabel('品牌')
plt.ylabel('销售量')
plt.title('喜好品牌分布')

plt.show()
#销售量排名前五的品牌是samsung、apple、ava、tefal、lg;

在这里插入图片描述

#按电子产品类别分类
category = df.groupby('category_code')['user_id'].count().sort_values(ascending=False).head(20)
category.plot(kind='bar')
plt.xlabel('产品类别')
plt.ylabel('销售量')
plt.title('喜好的产品类别分布')

plt.show()

#销售量排名前五的产品类别是(除others):智能手机、笔记本、冰箱、耳机、电视机;    

在这里插入图片描述

七、用户消费特征分析

1.用户整体消费分析

1)销售金额、订单数量、消费人数、客单价
2)订单数随星期的变化、订单数随小时的变化

fig, ax = plt.subplots(4, 1, figsize=(12,16))

#每月销售金额
df.groupby('date')['price'].sum().plot(ax=ax[0])
ax[0].set_ylabel('销售金额')
ax[0].set_title('销售金额')

#每月订单数量
df.groupby('date')['order_id'].nunique().plot(ax=ax[1])
ax[1].set_ylabel('订单数量')
ax[1].set_title('订单数量')

#每月消费人数
df.groupby('date')['user_id'].nunique().plot(ax=ax[2])
ax[2].set_ylabel('消费人数')
ax[2].set_title('消费人数')

#每月客单价(ATV:Average transaction value)
sale_amount = df.groupby('date')['price'].sum()
user_count = df.groupby('date')['user_id'].nunique()
sale_user = pd.merge(sale_amount,user_count,on='date')
sale_user.rename(columns={'price':'sale_amount', 'user_id':'user_count'}, inplace=True)
sale_user['ATV'] = round(sale_user['sale_amount']/sale_user['user_count'],1)
sale_user['ATV'].plot(ax=ax[3])
ax[3].set_xlabel('日期')
ax[3].set_ylabel('客单价')
ax[3].set_title('客单价')

fig.subplots_adjust(hspace=0.3)
plt.show()

#销售金额和订单数量的走势基本保持一致,1-4月销售额和单量较少且保持稳定,4月底开始上升,8月达到顶峰,9月开始下降,10月回升;
#消费人数有两个高峰,一个是在5月份,另一个是在7-9月,猜测是五一活动、暑期活动(6-8月份)和开学季(9月);
#其中8月份的消费人数远高于其他月份,是整年营收的关键时期,需提前准备好各类资源,运营计划、库存、物流、客服资源等;
#客单价4月-7月均处于较低水平,10-11月的客单价较高;

在这里插入图片描述

#订单数随星期分布
fig,ax = plt.subplots(1,2, figsize=(12,4))

custom_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
data = df.groupby('dayofweek')['order_id'].nunique()
weekday_categories = pd.Categorical(data.index, categories=custom_order, ordered=True)
week_order = pd.Series(data.values, index=weekday_categories)
week_order.sort_index().plot(ax=ax[0])
ax[0].set_xlabel('星期')
ax[0].set_ylabel('订单量')
ax[0].set_title('订单数随星期分布')

#订单数随小时分布
df.groupby('hour')['order_id'].nunique().plot(kind='bar', ax=ax[1],color='orange')
ax[1].set_xlabel('时')
ax[1].set_ylabel('订单量')
ax[1].set_title('订单数随小时分布')

fig.subplots_adjust(wspace=0.5)
plt.show()

#订单数随星期分布:周五的订单数量最低,周六最高,周日低于周六,但比工作日高;
#订单数随小时分布:大部分用户会在13-20时下单;
#结论:周末以及13-20点销量较高,需额外关注网站的运行稳定性;

在这里插入图片描述

2.用户个人消费分析

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

#用户消费次数
user_consume_count = df.groupby('user_id')['order_id'].nunique()
user_consume_count.describe()

#用户消费次数的均值为4,最小值为1,75%为3次,最大值为666次;
count    93804.000000
mean         4.261311
std         18.140393
min          1.000000
25%          1.000000
50%          2.000000
75%          3.000000
max        666.000000
Name: order_id, dtype: float64
#用户消费金额
user_consume_amount = df.groupby('user_id')['price'].sum()
user_consume_amount.describe()

#用户消费金额的均值为1249.54,最小值为0.02,75%为1150.34,最大值为165439.03;
count     93804.000000
mean       1249.541926
std        4194.162345
min           0.020000
25%         145.120000
50%         458.910000
75%        1150.347500
max      165439.030000
Name: price, dtype: float64
#消费次数与消费金额关系
data = pd.merge(user_consume_count, user_consume_amount,on='user_id').rename(columns={'order_id':'count','price':'amount'})
correlation = data['count'].corr(data['amount'])
plt.figure(figsize=(10,8))
plt.scatter(data['count'], data['amount'])
plt.xlabel('消费次数')
plt.ylabel('消费金额')
plt.title('消费次数与消费金额的关系')

plt.text(300, 125000, 'Correlation: {:.3f}'.format(correlation))
plt.show()

#消费次数和消费金额之间的相关系数为0.940,高度相关,因此需通过各种方法提高用户的消费次数,以此来提高消费金额;

在这里插入图片描述

#用户累计消费金额占比分析(用户贡献度)
user_cumsum = user_consume_amount.sort_values().reset_index().rename(columns={'price':'amount'})
user_cumsum['cumsum'] = user_cumsum['amount'].cumsum().astype(int)
user_cumsum['prop'] = user_cumsum['cumsum'].apply(lambda x: x/user_cumsum['cumsum'].max())
user_cumsum.tail()
user_idamountcumsumprop
937991515915625514597888135925.071165958380.994743
938001515915625513577472136738.031167325760.995910
938011515915625512377088153588.551168861650.997220
938021515915625513695488160426.631170465910.998589
938031515915625512422912165439.031172120301.000000
user_cumsum['prop'].plot()
plt.show()
#共93804位用户,前80000名用户大约贡献了40%的销售额,后13804位用户则贡献了将近60%的销售额,符合二八定律,需对这部分用户重点维护;

在这里插入图片描述

3.用户消费周期分析

用户购买周期、用户生命周期

df.sort_values(by='event_time',ascending=True, inplace=True)
user_cycle = df.loc[:, ['event_time','order_id','user_id']]
user_cycle.drop_duplicates(inplace=True)
#用户购买周期
user_purchase_cycle = user_cycle.groupby('user_id').apply(lambda x: x['event_time']-x['event_time'].shift()).dt.days
print(user_purchase_cycle.describe())
print('\n')
user_purchase_cycle.hist(bins=20)
plt.grid(False)
plt.title('用户购买周期')
plt.show()

#用户购买周期的均值为9.6天,最大值为298天;
#大多数用户的购买周期小于6天;
#呈现典型的长尾分布,只有小部分用户的购买周期在50天以上,可在这批用户消费9天左右通过赠送优惠券等方式来刺激召回;
count    305924.000000
mean          9.646726
std          23.848902
min           0.000000
25%           0.000000
50%           0.000000
75%           6.000000
max         298.000000
Name: event_time, dtype: float64

在这里插入图片描述

#用户生命周期
user_life_cycle = user_cycle.groupby('user_id').apply(lambda x: x['event_time'].max()-x['event_time'].min()).dt.days
print(user_life_cycle.describe())
print('\n')

user_life_cycle.hist(bins=20)
plt.grid(False)
plt.title('用户生命周期')
plt.show()

#用户生命周期的均值为32天,中位数为0天(大多数用户只消费了一次),可在第30天左右对客户进行引导,促使其再次消费,延长生命周期;
#75%为42天,生命周期>42天的属于核心用户,需根据其特点推出针对性的营销活动,引导其持续消费;
count    93804.000000
mean        32.079965
std         57.461976
min          0.000000
25%          0.000000
50%          0.000000
75%         42.000000
max        319.000000
dtype: float64

在这里插入图片描述

八、用户分层分析

1.用户价值度分析—RFM模型

#RFM值处理
#R值:取date这列的最大值为2020年11月21日
#F值:取用户的购买次数
#M值:取用户的总消费金额
value = df.pivot_table(values=['date','order_id','price'], index='user_id', 
                       aggfunc={'date':'max','order_id':'nunique','price':'sum'})
value.rename(columns={'date':'R', 'order_id':'F', 'price':'M'}, inplace=True)
value['R'] = (value['R'].max() - value['R']).dt.days
value.head()
RFM
user_id
15159156254399518721351416.64
151591562544003840024256.43
1515915625440051712557530.34
151591562544009984012194935.60
15159156254401216001302182.83
#处理R值
value['R'] = pd.qcut(value['R'], q=4, labels=[4, 3, 2, 1], duplicates='drop').astype(int)
#处理F值
bins = [value['F'].quantile(i) for i in [0, 0.25, 0.5, 0.75, 1]]
bins = sorted(set(bins))  # 处理重复边界值
bins.insert(0,0)
value['F'] = pd.cut(value['F'], bins=bins, labels=[1, 2, 3, 4]).astype(int)
#处理M值
value['M'] = pd.qcut(value['M'], q=4, labels=[1, 2, 3, 4], duplicates='drop').astype(int)
value.head()
RFM
user_id
1515915625439951872112
1515915625440038400421
1515915625440051712444
1515915625440099840444
1515915625440121600122
value['R_value'] = value['R'].apply(lambda x: 0 if x > value['R'].mean() else 1).astype(str)
value['F_value'] = value['F'].apply(lambda x: 0 if x < value['F'].mean() else 1).astype(str)
value['M_value'] = value['M'].apply(lambda x: 0 if x < value['M'].mean() else 1).astype(str)
value['RFM'] = value['R_value'] + value['F_value'] + value['M_value']
def RFM_func(data):
    d = {
    '000':'一般挽留用户',
    '100':'一般发展用户',
    '010':'一般保持用户',
    '110':'一般价值用户',
    '001':'重要挽留用户',
    '101':'重要发展用户',
    '011':'重要保持用户',
    '111':'重要价值用户' 
    }
    result = d[data]
    return result

value['类别'] = value['RFM'].apply(RFM_func)
value.head()
RFMR_valueF_valueM_valueRFM类别
user_id
1515915625439951872112100100一般发展用户
1515915625440038400421000000一般挽留用户
1515915625440051712444011011重要保持用户
1515915625440099840444011011重要保持用户
1515915625440121600122100100一般发展用户
value[['类别','RFM']].groupby('类别').count().sort_values(by='RFM', ascending=False).plot(kind='bar')
plt.legend(labels=[])
plt.xlabel('类别', loc='right')
plt.ylabel('用户数量', loc='top')
plt.show()

#一般发展用户数量最多,其次是重要保持用户和一般挽留用户;

在这里插入图片描述

2.用户活跃度分析

#未注册用户
#新用户:之前从未购买
#活跃用户:上月有购买且本月有购买
#不活跃用户:本月未购买
#回流用户:上月未购买但本月购买
user_status = df.pivot_table(values='order_id', index='user_id',columns='month', aggfunc='count', fill_value=0)
user_status = user_status.applymap(lambda x: 1 if x>0 else 0)
def status_judge(data):
    status = []    
    for i in range(11):
        if data.iloc[i] == 0:
            if len(status) == 0:
                status.append('unreg')
            else:
                if status[i-1] == 'unreg':
                    status.append('unreg')
                else:
                    status.append('unactive')       
        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,user_status.columns)

user_status = user_status.apply(status_judge,axis=1)
user_status = user_status.replace('unreg',np.NaN).apply(lambda x: pd.value_counts(x)).fillna(0)
plt.figure(figsize=(12,8))
user_status.T.plot.area(color=['red','orange','green','gray'])
plt.show()

#新用户从3月份开始逐渐增加,8月份的新用户增加数量最多,8月之后开始逐渐减少;
#活跃用户从4月份开始逐渐增加,8月份活跃用户增量最多,8月份之后开始减少;
#不活跃用户从6月份开始增加,且增加的速度也越来越快;
#回流用户从5月份开始增加,直至7月份开始保持稳定状态;
<Figure size 1200x800 with 0 Axes>

在这里插入图片描述

九、复购率和回购率分析(月维度)

#每月复购率(同个月内消费多次的用户占总用户的比例)
plt.figure(figsize=(6,4))
purchase_r = df.pivot_table(values='order_id', index='user_id',columns='month', aggfunc='nunique', fill_value=0)
purchase_r = purchase_r.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
(purchase_r.sum()/purchase_r.count()).plot()
plt.title('复购率')
plt.show()

#从6月开始到10月复购率一直保持增长,10月份复购率最高,达到48%;
#复购率有3个小高峰,分别为3月、5月和10月,猜测与清明、五一和十一假期有关;

在这里插入图片描述

#每月回购率(在一个时间窗口内进行了消费,在下一时间窗口内也进行了消费)
purchase_b = df.pivot_table(values='order_id', index='user_id',columns='month', aggfunc='count', fill_value=0)
purchase_b = purchase_b.applymap(lambda x:1 if x>0 else 0)
def return_judge(data):
    status = []
    for i in range(10):
        if data.iloc[i] == 1:
            if data.iloc[i+1] == 1:
                status.append(1)
            elif data.iloc[i+1] == 0:
                status.append(0)
        else:
            status.append(np.NaN)
    status.append(np.NaN)    
    return pd.Series(status,purchase_b.columns)

purchase_b = purchase_b.apply(return_judge, axis=1)
plt.figure(figsize=(6,4))
(purchase_b.sum()/purchase_b.count()).plot()
plt.title('回购率')
plt.show()

#回购率从1月-11月呈现下降趋势,其中3月、5月、8月和10月下降的最严重,估计也与清明、五一、暑假和十一假期有关;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值