主要层次
使用Python将数据从数据库中取出并进行转换,根据用户个体行为,进行消费金额、购买量、消费次数等基本分析,同时用户进行分层,利用RFM模型进行深入分析
导包
连接数据库
观察是否需要重置索引、列名改为中文、数据类型处理、月份的提取
基本分析
- 不同月份用户消费金额
- 不同月份商品购买量
- 不同月份的消费次数
- 不同月份的消费人数
个体行为分析
- 用户消费金额与购买产品个数的关系(散点图)
- 直方图:用户购买数量分布+用户购买金额分布
- 首次消费人数与时间的关系
- 复购率
在某时间窗口内重复消费用户(消费两次及以上的用户)在总消费用户中占比
- 回购率
某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比
RFM
对应思维导图如下

代码
导包
import pymysql
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
连接数据库
## 连接数据库
db_info = {
"host":"****host",
"user":"username",
"password":"***********",
"database":"***database",
"charset":"utf8"
}
conn = pymysql.connect(**db_info)
cursor = conn.cursor()
sql = "select * from customer"
data = pd.read_sql(sql,conn)
data.head()

# 重置索引
data = data.set_index('id')
# 列名改为中文
data.columns = ['用户id','订单时间','订单数量','订单金额']
data.head()

data.describe()

data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 2013 entries, 1 to 2013
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 用户id 2013 non-null object
1 订单时间 2013 non-null object
2 订单数量 2013 non-null object
3 订单金额 2013 non-null object
dtypes: object(4)
memory usage: 78.6+ KB
# 订单时间格式变为datetime64
data['订单时间'] = data['订单时间'].astype('datetime64')
# 订单数量和订单金额变为int
data['订单数量']=data['订单数量'].astype(int)
data['订单金额']=data['订单金额'].astype(int)
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 2013 entries, 1 to 2013
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 用户id 2013 non-null object
1 订单时间 2013 non-null datetime64[ns]
2 订单数量 2013 non-null int32
3 订单金额 2013 non-null int32
dtypes: datetime64[ns](1), int32(2), object(1)
memory usage: 62.9+ KB
data.describe()

data.head()

# 提取月份
data['月份']=data['订单时间'].dt.month
data.head()

# 不同月份用户消费金额
d = data.groupby('月份')['订单金额'].sum()
d
月份
1 3401
2 2032
3 5917
4 1869
5 3095
6 4142
7 5333
8 3805
9 2621
10 5855
11 3861
12 4157
Name: 订单金额, dtype: int32
plt.figure(figsize=(20,5))
font = {'family':'SimHei',
'size':20}
plt.rc('font',**font)
plt.plot(d)
plt.xlabel('月份')
plt.ylabel('订单金额')
plt.title('不同月份用户消费金额')
plt.show()

# 不同月份商品购买量
num = data.groupby('月份')['订单数量'].sum()
num
月份
1 188
2 140
3 50
4 109
5 233
6 296
7 403
8 333
9 377
10 225
11 330
12 273
Name: 订单数量, dtype: int32
plt.figure(figsize = (20,5))
font = {'family':'SimHei','size':20}
plt.rc('font',**font)
plt.plot(num)
plt.xlabel('月份')
plt.ylabel('商品购买量')
plt.title('不同月份商品购买量')
plt.show()

# 不同月份的消费次数
times = data.groupby('月份')['用户id'].count()
times
月份
1 163
2 111
3 35
4 92
5 145
6 172
7 272
8 229
9 199
10 162
11 223
12 210
Name: 用户id, dtype: int64
plt.figure(figsize = (20,5))
font = {'family':'SimHei','size':20}
plt.rc('font',**font)
plt.plot(times)
plt.xlabel('月份')
plt.ylabel('用户消费次数')
plt.title('不同月份消费次数')
plt.show()

# 不同月份的消费人数
num = data.groupby('月份').nunique()['用户id']
num
月份
1 31
2 17
3 13
4 9
5 18
6 25
7 74
8 90
9 68
10 41
11 36
12 27
Name: 用户id, dtype: int64
plt.figure(figsize = (20,5))
plt.font = {'family':'SimHei','size':'20'}
plt.rc('font',**font)
plt.plot(num)
plt.xlabel('月份')
plt.ylabel('用户消费数量')
plt.title('不同月份用户消费数量')
plt.show()

个体行为分析
data.head()
# 用户消费金额与购买产品个数的关系(散点图)
user_consumer = data.groupby('用户id').sum()
user_consumer

plt.figure(figsize = (20,5))
plt.font = {'family':'simHei','size':'20'}
plt.rc('font',**font)
plt.scatter(user_consumer['订单数量'],user_consumer['订单金额'])
plt.xlabel('订单数量')
plt.ylabel('不同用户订单金额')
plt.title('用户消费金额与购买产品个数的关系')
plt.show()

# 直方图:用户购买数量分布+用户购买金额分布
consumer_products = user_consumer['订单数量']
consumer_amount = user_consumer['订单金额']
plt.figure(figsize = (20,5))
plt.font = {'family':'simHei','size':'20'}
plt.rc('font',**font)
plt.subplot(121)
plt.hist(consumer_products)
plt.xlabel('用户购买数量')
plt.ylabel('人数')
plt.title('用户购买数量分布')
plt.subplot(122)
plt.hist(consumer_amount)
plt.xlabel('用户购买金额')
plt.ylabel('人数')
plt.title('用户购买金额分布')
plt.show()

# 首次消费人数与时间的关系
data.head(10)

d = data.groupby('用户id')['月份'].min().value_counts()
d.sort_index(inplace = True)
d
1 31
2 7
3 6
4 1
5 5
6 9
7 48
8 62
9 42
10 19
11 13
12 4
Name: 月份, dtype: int64
plt.figure(figsize = (20,5))
plt.font = {'family':'simHei','size':'20'}
plt.rc('font',**font)
plt.plot(d)
plt.xlabel('第一次消费所在月份')
plt.ylabel('人数')
plt.title('首次消费人数与时间的关系')
plt.show()

# 复购率
# 利用透视表统计用户消费次数
pivoted_counts = data.pivot_table(index = '用户id',columns = '月份',
values='订单时间',aggfunc = 'count').fillna(0)
pivoted_counts

# 确定用户是否有回购的行为 (当月>1次为回购1,0次为NaN,1次和其它次其它为0)
pivoted_counts.transf = pivoted_counts.applymap(
lambda x: 1 if x >1 else np.NaN if x==0 else 0)
pivoted_counts.transf.head()

pivoted_counts.transf.sum()
月份
1 21.0
2 14.0
3 8.0
4 9.0
5 16.0
6 17.0
7 48.0
8 50.0
9 44.0
10 27.0
11 24.0
12 19.0
dtype: float64
## 每个月的复购率折线图
plt.figure(figsize=(20,5))
month_counts_reorder_rate = pivoted_counts.transf.sum()/pivoted_counts.transf.count()
plt.font = {'family':'SimHei','size':'20'}
plt.rc("font",**font)
plt.plot(month_counts_reorder_rate)
plt.xlabel('复购行为所在月份')
plt.ylabel('复购率')
plt.title('每月的复购率')
plt.show()

# 每月消费和二次消费的用户数
a,b = plt.subplots(figsize=(20,5))
b.plot(pivoted_counts.transf.count())#非NaN的数目,即消费的人数
b.plot(pivoted_counts.transf.sum())#1的数目,即当月2次消费的人数
b.legend(['消费人数','二次消费以上的人数'])
plt.title('每月消费和二次消费的用户数')
plt.xlabel('月份')
plt.ylabel('用户数')
plt.show()

RFM
- R:最近一次消费 recency
- F:消费频率 frequency
- M:消费金额 monetary
user_rfm = data.pivot_table(index = '用户id',values = ['订单时间','订单数量','订单金额'],
aggfunc = {'订单时间':'max','订单数量':'count','订单金额':'sum'})
user_rfm.head()

# R:最近一次消费,我们现在假设时间是2021-1-1
user_rfm['最近一次消费']=(pd.to_datetime('2021-01-01 00:00:00')-user_rfm['订单时间'])
/np.timedelta64(1,'D')
user_rfm['最近一次消费']
用户id
vs10000005 370.386944
vs10000621 308.000000
vs10000627 528.000000
vs10000716 308.000000
vs10000743 658.000000
...
vs30033640 344.664410
vs30033645 344.307813
vs30033648 343.547280
vs30033726 325.000000
vs30033728 321.348137
Name: 最近一次消费, Length: 247, dtype: float64
user_rfm.head()

user_rfm.columns = ['F','订单时间','M','R']
user_rfm.head()
方法2:
user_rfm = user_rfm.rename(columns={'最近一次消费':"R",'订单数量':"F",'订单金额':"M"})

## 给用户贴上标签
def rfm_func(x):
level = x.apply(lambda x:"1" if x>=0 else "0")
label = level.R + level.F + level.M
d = {
'111':'高价值用户',
'011':'重点保持客户',
'101':'重点发展客户',
'001':'重点挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'潜在客户'
}
result = d[label]
return result
# 和平均值作比较确定RFM
user_rfm['label']=user_rfm[['R','F','M']].apply(lambda x : x-x.mean()).apply(rfm_func,
axis=1)
user_rfm.head(10)
## 我们来观察一下每一个级别的用户的数量
user_rfm.groupby('label').count()['F']
label
一般保持客户 3
一般发展客户 144
潜在客户 65
重点保持客户 24
重点发展客户 2
重点挽留客户 2
高价值用户 7
Name: F, dtype: int64
plt.figure(figsize=(20,10))
plt.pie(user_rfm.groupby('label').count()['F']
,labels=['一般保持客户','一般发展客户','潜在客户'
,'重点保持客户','重点发展客户','重点挽留客户','高价值客户']
,autopct='%.2f%%'
,explode=(0,0,0,0.1,0.2,0.3,0.5)
)
plt.title('用户分层占比')
plt.show()
