客户消费行为分析

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from datetime import datetime
import os
plt.style.use('ggplot') #更改绘图风格,R语言绘图库的风格
font=FontProperties(fname='/System/Library/Fonts/Supplemental/Arial Unicode.ttf',size=10)


filepath='/Users/kangyongqing/Documents/kangyq/202303/分析模版/客户消费行为分析/'
file1='01fufeidetail.csv'
#redshift下载付费明细文件导入

df=pd.read_csv(os.path.join(filepath,file1),dtype={'parent_user_id':'object'},parse_dates=['付费时间'])  #可直接导入日期格式
df['product']=1
df=df[(df['total_amount']>=5)&(df['parent_user_id']!='8439620452226034')] #去除BL账号
# print(df.info())
# print(df.describe())
df['date1']=pd.to_datetime(df['date'],format='%Y-%m-%d') #若日期字段非时间格式,可以用该办法替换
df['month']=df['date1'].astype('datetime64[M]')  #[M]:控制转换后的精度
# print(df.head(1).T)
print(df.describe())

#part1 用户整体消费趋势分析(按月份)
#按月份统计产品购买数量,消费金额,消费次数,消费人数

plt.figure(figsize=(12,8))
#每月的产品购买数量
plt.subplot(221) #两行两列,占第一个位置
df.groupby(by='month')['total_amount'].sum().plot() #默认折线图
plt.title('每月的课时购买数量',font=font)
plt.subplot(222) #两行两列,占第二个位置
df.groupby(by='month')['total_amount'].sum().plot() #默认折线图
plt.title('每月的消费金额',font=font)
plt.subplot(223) #两行两列,占第二个位置
df.groupby(by='month')['product'].count().plot() #默认折线图
plt.title('每月的消费次数',font=font)
plt.subplot(224) #两行两列,占第二个位置
df.groupby(by='month')['parent_user_id'].apply(lambda x:len(x.drop_duplicates())).plot() #默认折线图
plt.title('每月的消费人数',font=font)
plt.savefig(filepath+'01购买力.png')
plt.show()


#part2 用户个体消费分析
user_grouped=df.groupby(by='parent_user_id').sum()
print(user_grouped.describe())
print('用户数量',len(user_grouped))

#part3 用户消费分布图

plt.figure(figsize=(12,6))
plt.subplot(121)
plt.xlabel('每个订单的消费课时',font=font)
df['total_amount'].plot(kind='hist',bins=50)  #bins:区间分数,影响柱子的宽度,值越大柱子越细。宽度=(列最大值-列最小值

plt.subplot(122)
plt.xlabel('每个家长id购买的数量',font=font)
df.groupby(by='parent_user_id')['product'].sum().plot(kind='hist',bins=50)
plt.savefig(filepath+'02购买力.png')
plt.show()

#part4 用户累计消费课时占比分析(用户的贡献度)
#进行用户分组,取出购买课时,进行求和,排序,重置索引
user_cumsum=df.groupby(by='parent_user_id')['total_amount'].sum().sort_values().reset_index()
print(user_cumsum)

#每个用户消费课时累加
user_cumsum['amount_cumsum']=user_cumsum['total_amount'].cumsum()
# print(user_cumsum.tail())

#消费总课时
amount_total=user_cumsum['amount_cumsum'].max()
# print(amount_total)
#前XX名用户的总贡献率
user_cumsum['prop']=user_cumsum.apply(lambda x:x['amount_cumsum']/amount_total,axis=1)
print(user_cumsum.tail())
user_cumsum['prop'].plot()
plt.title('用户贡献率',font=font)
plt.savefig(filepath+'03贡献率.png')
plt.show()

#part5 用户消费行为
#用户分组,取最小时间,即首购时间
df.groupby(by='parent_user_id')['date1'].min().value_counts().plot()
plt.title('首购分布',font=font)
plt.savefig(filepath+'04首购分布.png')
plt.show()
#最后一次购买时间
df.groupby(by='parent_user_id')['date1'].max().value_counts().plot()
plt.title('最后一次购买时间分布',font=font)
plt.savefig(filepath+'05最后一次购买时间.png')
plt.show()

#part6 用户分层
#构建RFM模型分析并可视化
rfm=df.pivot_table(index='parent_user_id',
                   values=['product','total_amount','date1'],
                   aggfunc={
                       'product':'sum', #购买总次数
                       'total_amount':'sum', #购买总课时
                       'date1':'max' #最后一次购买
                   })
print(rfm.head())
#每个用户的最后一次购买时间-日期列中的最大值,最后再转换成天数,小数保留一位
rfm['R']=-(rfm['date1']-rfm['date1'].max())/np.timedelta64(1,'D')
rfm.rename(columns={'product':'F','total_amount':'M'},inplace=True)
print(rfm.head())

#RFM计算方式:每一列数据减去数据所在列的平均值,有正有负,根据结果值与1做比较,如果>=1,设置为1,否则0
def rfm_func(x): #x分别代表每一列数据
    level=x.apply(lambda x:'1' if x>=1 else '0')
    label=level['R']+level['F']+level['M']  #举例:100,001
    d={
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要发展客户',
        '001':'重要挽留客户',
        '110':'一般价值客户',
        '010':'一般保持客户',
        '100':'一般发展客户',
        '000':'一般挽留客户'
    }
    result=d[label]
    return result
#frm['R']-rfm['r'].mean()
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
print(rfm.head())

#客户分层可视化
for label,grouped in rfm.groupby(by='label'):
    x=grouped['F']
    y=grouped['R']
    plt.scatter(x,y,label=label)

plt.legend(prop=font) #显示图例,prop处理中文
plt.xlabel('F')
plt.ylabel('R')
plt.savefig(filepath+'06RFM分层.png')
plt.show()


#新老、活跃、回流用户分析
#新用户的定义是第一次消费;
# 活跃用户即老客,在某一个时间段内有过消费;
# 不活跃用户则是时间窗口内没有消费过的老客;
# 回流用户:相当于回头客的意思;
# 用户回流的动作可以分为自主回流和人工回流,自主回流指客户自己回流了,而人工回流则是人为参与导致的;
pivoted_counts=df.pivot_table(
    index='parent_user_id',
    columns='month',
    values='date',
    aggfunc='count'
).fillna(0)
print(pivoted_counts.head())

#由于浮点数不直观,并且需要转换成是否消费过即可,用0,,1表示

df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
#apply:作用于dataframe数据中的一行或者一列数据
#applymap:作用于dataframe数据中的每个元素
#map:本身是一个series的函数,在df结构中无法使用map函数,map函数作用域series中的每一个元素
print(df_purchase.head())
print(df_purchase.shape)

def active_status(data):#data:每一行数据(共75列)
    status=[] #存储用户75个月的状态(new/active/unactive/return/unreg)
    for i in range(75):
        # 判断本月没有消费==0
        if data[i]==0:
            if len(status)==0: #前几个月没有任何记录
                status.append('unreg')
            else: #之前的月份有记录(判断上一个月状态)
                if status[i-1]=='unreg': #一直没有消费过
                    status.append('unreg')
                else: #上个月的状态可能是:new/active/unactive/return
                    status.append('unactive')
        else: #本月有消费==1
            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 pd.Series(status,df_purchase.columns) #值:status,列名:75个月份


purchase_states=df_purchase.apply(active_status,axis=1)  #得到用户分层结果
print(purchase_states.head())

#把unreg状态用nan替换
purchase_states_ct=purchase_states.replace('unreg',np.NAN).apply(lambda x:pd.value_counts(x))
print(purchase_states_ct.head())

#数据可视化,面积图

purchase_states_ct.fillna(0).T.plot.area(figsize=(12,6)) #填充nan之后,进行行列变换
plt.savefig(filepath+'07活跃面积图.png')
plt.show()

#每月中回流用户占比情况(占所有用户的比例)
plt.figure(figsize=(12,6))
rate=purchase_states_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
plt.plot(rate['return'],label='return')
plt.plot(rate['active'],label='active')
plt.legend()
plt.savefig(filepath+'08回流用户.png')
plt.show()


#用户的购买周期
# shift函数:将数据移动到一定的位置
data1=pd.DataFrame({
    'a':[0,1,2,3,4,5],
    'b':[5,4,3,2,1,0]
})
print(data1)
print(data1.shift(axis=0)) #整体乡下移动一个位置(默认值:axis=0)
print(data1.shift(axis=1))

#计算购买周期(购买日期的时间差值)
order_diff=df.groupby(by='parent_user_id').apply(lambda x:x['date1']-x['date1'].shift(periods=-1))
print(order_diff.describe())
(order_diff/np.timedelta64(1,'D')).hist(bins=20) #影响柱子的宽度,每个柱子的宽度=(最大值-最小值)/bins
plt.savefig(filepath+'081购买周期.png')
plt.show()

#part7 用户生命周期

user_life=df.groupby('parent_user_id')['date1'].agg(['min','max'])
(user_life['max']==user_life['min']).value_counts().plot.pie(autopct='%1.1f%%') #格式化成1位小数
plt.legend(['仅消费一次','多次消费'],prop=font)
plt.savefig(filepath+'09多次消费.png')
plt.show()

#绘制所有用户生命周期直方图+多次消费

plt.figure(figsize=(12,6))
plt.subplot(121)
((user_life['max']-user_life['min'])/np.timedelta64(1,'D')).hist(bins=15)
plt.title('所有用户生命周期直方图',font=font)
plt.xlabel('生命周期天数',font=font)
plt.ylabel('用户人数',font=font)

plt.subplot(122)
u_1=(user_life['max']-user_life['min']).reset_index()[0]/np.timedelta64(1,'D')
u_1[u_1>0].hist(bins=15)
plt.title('多次消费的用户生命周期直方图',font=font)
plt.xlabel('生命周期天数',font=font)
plt.ylabel('用户人数',font=font)
plt.savefig(filepath+'10用户生命周期.png')
plt.show()


#part8 复购率和回购率分析
#复购率分析
#计算方式:在自然月内,购买多次的用户在总消费人数中的占比(若客户在同一天消费了多次,也称之为复购用户)
#消费者有三种:消费记录>=2次的;消费中人数;本月无消费用户;
#复购用户:1 非复购的消费用户:0 自然月内没有消费记录的用户:NAN(不参与count计数)
purchase_r=pivoted_counts.applymap(lambda x:1 if x>1 else np.NAN if x==0 else 0)
print(purchase_r.head())
print("复购用户数:",purchase_r.sum()) #:求出复购用户
#purchase_r.count():求出所有参与购物的用户(NAN不参与计数)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(12,6))
plt.title('复购用户占比',font=font)
plt.savefig(filepath+'11复购用户.png')
plt.show()

#回购率分析
#计算方式:在一个时间窗口内进行了消费,在下一个时间窗口内又进行了消费
def purchase_back(data):
    status=[] #存储用户回购率状态
    #1:回购用户  0:非回购用户(当前月消费了,下个未消费) NAN:当前月份未消费
    for i in range(74):
        #当前月份消费了
        if data[i]==1:
            if data[i+1]==1:
                status.append(1) #回购用户
            elif data[i+1]==0:#下个月未消费
                status.append(0)
        else:#当前月份未进行消费
            status.append(np.NAN)
    status.append(np.NAN) #填充最后一列数据
    return pd.Series(status,df_purchase.columns)

purchase_b=df_purchase.apply(purchase_back,axis=1)
print(purchase_b.head())

#回购率可视化
plt.figure(figsize=(12,4))
plt.subplot(211)
#回购率
(purchase_b.sum()/purchase_b.count()).plot(label='回购率')
#复购率
(purchase_r.sum()/purchase_r.count()).plot(label='复购率')
plt.legend(prop=font)
plt.ylabel('百分比',font=font)
plt.title('用户回购率和复购率对比图',font=font)
plt.savefig(filepath+'12回购率和复购率对比.png')
plt.show()


#方法总结
#1、针对用户按照月份做整体和个体分析,主要分析维度是人数,消费金额,购买量
#2、消费分析:首购时间,最后一次购买时间,相邻两个购买时间的间隔,用户分层(RFM模型+数据透视表),分析维度主要是新用户,活跃用户,不活跃用户流失分析,回流用户占比
#3、复购率和回购率进行分析




猜你喜欢

转载自blog.csdn.net/Darin2017/article/details/132424860