0
点赞
收藏
分享

微信扫一扫

Python、SQL:健身俱乐部用户消费行为分析

南柯Taylor 2021-09-28 阅读 57

主要层次

使用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()

举报

相关推荐

0 条评论