单车案例分析

目录

  • 分析目标
  • 分析过程
  • 总结建议

一、分析目标

本次分析报告的数据来源与这家单车网站上的用户消费记录,通过分析用户消费行为,建立RFM模型,分析复购率、回购率等关键指标,对该产品的线上消费数据进行分析并提出有价值的建议。

二、分析思路与过程

分析思路

分析过程

0、数据集的观察与清洗

(1)导入数据包

import pandas as pd  
import numpy as np

(2)导入数据集

columns=['user_id','order_dt','order_products','order_amount']
df=pd.read_table('D:\\Users\\yuan\\Desktop\\bicycle_master.txt',names=columns, sep='\s+')

(3)数据集清洗

查看数据是否有缺失

df.info()


大部分订单只消费了少量商品(平均2.4),有一定值干扰
用户的消费金额比较稳定,平均消费35元,中位数在35元,有一定极值的干扰

df['order_dt']=pd.to_datetime(df.order_dt,format="%Y%m%d")
df['month']=df.order_dt.values.astype('datetime64[M]')

对时间进行解析,一开始默认的格式是 int64的,可以用 df.info() 来查看,默认会是 datetime64[ns] 类型,后面中括号表示 时间间隔是 ns
下面是对 order_dt 列(取values),转换类型为datetime64[M],默认就会是每月的第一天了,同理设置为[Y]就是每年的1月1日,然后生成新的一列 month

1、进行用户消费趋势的分析(按月)

(1)每月的消费总金额

grouped_month=df.groupby('month')
order_month_amount=grouped_month.order_amount.sum()
order_month_amount.head()

(2)每月的消费次数

(3)每月的产品购买量

grouped_month_info = grouped_month[['order_amount','user_id','order_products']].agg({'order_amount':sum, 'user_id': 'count', 'order_products':sum})
grouped_month_info.rename(columns = {'order_amount':'消费金额', 'user_id': '消费次数', 'order_products': '产品购买量'}, inplace=True)
grouped_month_info

(4)每月的消费人数

grouped_month_info['消费人次'] = grouped_month['user_id'].unique().map(len)
grouped_month_info = grouped_month_info.reset_index()
grouped_month_info['month'] = grouped_month_info['month'].astype(str)

grouped_month_info['month'] = grouped_month_info['month'].astype(str)
grouped_month_info.to_excel('D:\\Users\\yuan\\Desktop\\临时表\月销售额、销售次数、产品购买量、消费人数.xlsx')

由上图可知,消费金额在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势


由上图可知,产品购买量在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势


前三个月消费订单人数在10000笔左右,后续月份的平均消费人数则在2500人
去重的方法有多种,这里也可以使用数据库思想,df.groupby(['month','user_id']).count().reset_index()
每月消费人数低于每月消费次数,但差异不大
前三个月每月的消费人数在8000-10000之间,后续月份,平均消费人数在2000不到

# 上面进行的汇总分析,其实可以用数据透视的方法更快实现,一次性求出结果
df.pivot_table(index='month',
              values=['order_products','order_amount','user_id'],
              aggfunc={'order_products':'sum',
                      'order_amount':'sum',
                      'user_id':'count'}).head()
  • 每月用户平均消费金额的趋势
amount=grouped_month.order_amount.sum()
num=df.groupby('month').user_id.apply(lambda x:len(x.drop_duplicates()))
avg_amount=amount/num
  • 每月用户平均消费次数的趋势
times=grouped_month.user_id.count()
num=df.groupby('month').user_id.apply(lambda x:len(x.drop_duplicates()))
avg_times=times/num

2.用户个体消费分析

  • 用户消费金额和消费次数的散点图
  • 用户消费金额的分布图
  • 用户消费次数的分布图
  • 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)

(1)用户消费金额,消费次数的描述统计

grouped_user=df.groupby('user_id')

grouped_user.sum().describe()

用户平均购买了7张,但是中位值只有3,说明小部分用户购买了大量货物
用户平均消费106元,中位值有43,判断同上,有极值干扰

grouped_user_info = grouped_user.sum()

grouped_user_info.to_excel('D:\\Users\\yuan\\Desktop\\临时表\用户个体消费行为分析.xlsx')
grouped_user_info
grouped_user_sum_order_amount = grouped_user.sum().order_amount
grouped_user_sum_order_amount_lst = [i for i in range(0,int(grouped_user_sum_order_amount.max())+1,50)]

grouped_user_sum_order_amount = pd.cut(grouped_user_sum_order_amount, bins=grouped_user_sum_order_amount_lst,labels = grouped_user_sum_order_amount_lst[1:])
pd.cut(grouped_user_sum_order_amount,bins=100)
grouped_user_sum_order_amount.to_excel('D:\\Users\\yuan\\Desktop\\临时表\消费金额分布直方图.xlsx')

从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断,可以使用过滤操作排除异常

使用切比雪夫定理过滤掉异常值,因为切比雪夫定理说明,95%的数据都分布在5个标准差之内,剩下5%的极值就不要了

order_amount (mean = 106 ,std = 241) mean+5std = 1311

grouped_user.sum().sort_values('order_amount').sum()
grouped_user.sum().sort_values('order_amount').cumsum()/grouped_user.sum().sort_values('order_amount').sum()
# cumsum 是求累加值
user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
# 这里 reset_index() 是为了得到一个自然数的行标签,表示的就是人数,下面的图就可以看出来多少个少占多少百分比
user_cumsum
user_cumsum.reset_index().order_amount.to_excel('D:\\Users\\yuan\\Desktop\\临时表\累积销售.xlsx')

按照用户消费金额进行升序排序,由图可以知道50%的用户仅贡献了11%的消费额度,而排名前5000的用户就贡献了60%的消费额度

3.用户消费行为

(1)用户第一次消费(首购)

grouped_user_min = grouped_user.min().order_dt.value_counts().reset_index().rename(columns={'index':'first_date'})
grouped_user_min['first_date'] =grouped_user_min['first_date'].astype(str)
grouped_user_min.to_excel('D:\\Users\\yuan\\Desktop\\临时表\用户首购.xlsx')
grouped_user_max = grouped_user.max().order_dt.value_counts().reset_index().rename(columns={'index':'last_date'})

grouped_user_max['last_date'] =grouped_user_max['last_date'].astype(str)

grouped_user_max.to_excel(r'.\临时表\用户最后一次购买.xlsx')

断崖式下跌很正常:可以理解用户流失比例基本一致,一开始用户迅猛增长数量比较多流失的也比较多,后面没有用户
用户最后一次购买的分布比第一次分布广
大部分最后一次购买,集中在前三个月,说明很多用户购买了一次后就不再进行购买
随着时间的递增,最后一次购买数量也在递增,消费呈现流失上升的状况(这也是正常,随着时间的增长,可能运营每跟上,或者用户忠诚度下降了)

(3)新老客户消费比

# 得到第一次和最后yc次消费情况,如果 min、max 日期相同,说明只消费了一次
user_life=grouped_user.order_dt.agg(['min','max'])
(user_life['min']==user_life['max'])
# 统计只消费了一次的用户
(user_life['min']==user_life['max']).value_counts()

有一半的用户,只消费了一次

(4) 每月新客占比

  #按月分组下的userid分组,求每月的最早购买日期和最晚消费日期
grouped_um = df.groupby(['month','user_id']).order_dt.agg(["min","max"])  
  # 新增列 True 为 新用户
grouped_um["new"] = (grouped_um["min"] == grouped_um["max"] )           
# 再次按month分组,计算新用户占比
user_life_month_pct=user_life_month.groupby('month').is_new.apply(lambda x:x.value_counts()/x.count()).reset_index()

(5)用户分层

# 画 RFM,先对原始数据进行透视
rfm=df.pivot_table(index='user_id',
                  values=['order_products','order_amount','order_dt'],
                  aggfunc={'order_dt':'max',
                          'order_amount':'sum',
                          'order_products':'sum'})
rfm.head()
-(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1,'D')
# 得到最近一次消费,一般是计算 today 距离最近一次消费,这里因为时间太久远,就随便用的max值
# 数值越大就越久远,分子得到的是一些天数类似 545 days(因为是时间格式相减),处以一个单位,就不会有单位了只留下数值
rfm['R']= (rfm.order_dt - rfm.order_dt.max())/np.timedelta64(1,'D')
# 重命名,也就是 R:最后一次消费距今天数,F:消费总金额 ,M:消费总产品数
# R :消费时间  F:消费金额  M:消费频次
rfm.rename(columns={'order_products':"F",'order_amount':'M'},inplace=True)
rfm[['R','F','M']].apply(lambda x:x-x.mean())
def rfm_func(x):
    level=x.apply(lambda x:'1' if x>=0 else '0')
    # level 的类型是 series,index 是 R、F、M
#     print(type(level))
#     print(level.index)
    label=level.R + level.F + level.M
    d={
        # R 为1 表示离均值较远即时间很久,F为1 表示 消费金额比较多,M 为1 表示消费频次比较多,所以是重要价值客户
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要发展客户',
        '001':'重要挽留客户',
        '110':'一般价值客户',
        '010':'一般保持客户',
        '100':'一般发展客户',
        '000':'一般挽留客户',
    }
    result=d[label]
    return result
# 注意这里是要一行行的传递进来,所以 axis=1,传递一行得到一个 111,然后匹配返回一个值
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.loc[rfm.label=='重要价值客户','color']='重要价值客户'
rfm.loc[~(rfm.label=='重要价值客户'),'color']='非重要价值客户'
rfm
rfm.to_excel('D:\\Users\\yuan\\Desktop\\临时表\RFM模型.xlsx')
rfm.groupby('label').sum()

从RFM 分层可知,大部分用户是重要保持客户,但是这是由于极值的影响,所以 RFM 的划分标准应该以业务为准,也可以通过切比雪夫去除极值后求均值,并且 RFM 的各个划分标准可以都不一样
尽量用小部分的用户覆盖大部分的额度
不要为了数据好看划分等级

(6)用户生命周期

新客,活跃,回流,流失(一段时间不消费,或者不活跃)

# 数据透视, userid为索引,月为列,求每月的消费次数,这里填充了
pivoted_counts=df.pivot_table(index='user_id',
                             columns='month',
                             values='order_dt',
                             aggfunc='count').fillna(0)
pivoted_counts.head()
# 转变一下消费,有消费为1,没有消费为0
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
df_purchase.tail()
# 这里由于进行数据透视,填充了一些 null 值为0,而实际可能用户在当月根本就没有注册,
#这样会误导第一次消费数据的统计,所以写一个函数来处理
def active_status(data):
    status=[]
    # 数据一共有18个月份,每次输入一行数据,这样进行逐月判断
    for i in range(18):
        # 若本月没有消费,上面处理过的结果
        if data[i]==0:
            if len(status)>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

若本月没有消费,这里只是和上个月判断是否注册,有缺陷,可以判断是否存在就可以了

  • 若之前是未注册,则依旧为未注册
  • 若之前有消费,则为流失/不活跃
  • 其他情况,为未注册

若本月有消费

  • 若是第一次消费,则为新用户
  • 如果之前有过消费,则上个月为不活跃,则为回流
  • 如果上个月为未注册,则为新用户
  • 初次之外,为活跃

return:回流

new:新客

unreg:未注册

active:活跃

purchase_stats=df_purchase.apply(lambda x: pd.Series(active_status(x),index=df_purchase.columns),axis=1)
purchase_stats.head()
# 这里把未注册的替换为空值,这样 count 计算时不会计算到
# 得到每个月的用户分布
purchase_stats_ct=purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct
returnratee=purchase_stats_ct.apply(lambda x:x/x.sum(),axis=0)
returnratee
purchase_stats_ct_info = purchase_stats_ct.fillna(0).T
purchase_stats_ct_info
purchase_stats_ct_info.index = purchase_stats_ct_info.index.astype(str)

purchase_stats_ct_info.to_excel('D:\Users\yuan\Desktop\临时表\用户分层-新、活跃、流失、回流.xlsx')

# 求出所有用户的占比
purchase_stats_ct_T = purchase_stats_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
purchase_stats_ct_T
purchase_stats_ct_T / purchase_stats_ct_T.shift()
purchase_stats_ct_T.shift()

前三个月有大量新用户涌入,新用户占比很高,而后面几个月不活跃用户占比非常高,普遍在90%以上。
活跃用户,持续消费的用户,对应的是消费运营的质量。
回流用户,之前不消费,本月才消费,对应的是唤回运营。
不活跃用户,对应的是流失。

(6) 用户购买周期(按订单)

# 计算相邻两个订单的时间间隔,shift 函数是对数据进行错位,所有数据会往下平移一下,所以可以
order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
order_diff.head(10)
#描述性统计
order_diff.describe()
order_diff_info = (order_diff/np.timedelta64(1,'D'))
order_diff_cut_lst = [i for i in range(0,int(order_diff_info.max())+1,10)]
order_diff_info_hist = pd.cut(order_diff_info,bins=order_diff_cut_lst,labels=order_diff_cut_lst[1:])
order_diff_info_hist = order_diff_info_hist.fillna(10)

order_diff_info_hist.to_excel('D:\Users\yuan\Desktop\临时表\用户购买周期时间差频率直方图.xlsx')



订单周期呈指数分布
用户的平均购买周期是68天
绝大部分用户的购买周期都低于100天

(7)用户生命周期(按第一次和最后一次消费)

#描述性统计
(user_life['max']-user_life['min']).describe()
user_life_info = ((user_life['max']-user_life['min'])/np.timedelta64(1,"D"))
user_life_lst = [i for i in range(0,int(user_life_info.max())+1,10)]
user_life_info_hist = pd.cut(user_life_info,bins=user_life_lst,labels=user_life_lst[1:])
user_life_info_hist
user_life_info_hist_2 = user_life_info_hist.fillna(10)
user_life_info_hist_2.to_excel('D:\\Users\\yuan\\Desktop\\临时表\用户生命周期频率直方图.xlsx')

用户的生命周期受只购买一次的用户影响比较厉害(可以排除)
用户均消费134天,中位数仅0天

user_life["差值"]=(user_life["max"] - user_life["min"])/np.timedelta64(1,"D")
user_life.head(5)
user_life_info_hist.to_excel('D:\\Users\\yuan\\Desktop\\临时表\用户生命周期频率直方图(忽略一次购买).xlsx')

4.复购率和回购率分析

复购率
自然月内,购买多次的用户占比(即,购买了两次以上)
回购率
曾经购买过的用户在某一时期的再次购买的占比(可能是在三个月内)

(1) 复购率

#消费次数
pivoted_counts.head(10)
# 区分一个,和一个以上的情况,以便于计算复购率,大于1为1,等于0 为0,等于1为0 
purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
purchase_r_reshop = (purchase_r.sum()/purchase_r.count()).reset_index(name = 'reshop')
purchase_r_reshop
purchase_r_reshop['month'] = purchase_r_reshop['month'].astype(str)
purchase_r_reshop.to_excel('D:\\Users\\yuan\\Desktop\\临时表\复购人数与总消费人数比例.xlsx')

复购率稳定在20%所有,前一个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率降低

回购率

# 需要使用函数来判断是否回购:当月消费过的用户下个月也消费了叫做回购,这个定义可以改变
def purchase_back(data):
    '''判断每一个月是否是回购,根据上个月是否购买来判断,上个月消费下个月没有购买就不是回购'''
    status=[]
    for i in range(17):
        if data[i]==1:
            if data[i+1]==1:
                status.append(1)
            if data[i+1]==0:
                status.append(0)
        else:
            status.append(np.NaN)
    # 第18个月补充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()
purchase_b_backshop = purchase_b.sum()/purchase_b.count()
purchase_b_backshop.index
purchase_b_backshop.index = purchase_b_backshop.index.astype(str)
purchase_b_backshop.to_excel('D:\\Users\\yuan\\Desktop\\临时表\回购率.xlsx')

三、总结建议

1、用户消费趋势(每月)方面,前3个月有大量新用户涌入,消费金额、消费订单数、产品购买量均达到高峰,后续每月较为稳定。前3个月消费次数都在10000笔左右,后续月份的平均2500;前3个月产品购买量达到20000甚至以上,后续月份平均7000;前3个月消费人数在8000-10000之间,后续月份平均2000不到。
2、用户个体消费方面,小部分用户购买了大量的CD,拉高了平均消费金额。用户消费金额集中在0100元,有大约17000名用户。用户购买量集中在05,有大约16000名用户。50%的用户仅贡献了15%的消费额度,15%的用户贡献了60%的消费额度。大致符合二八法则。
3、用户消费行为方面,首购和最后一次购买的时间,集中在前三个月,说明很多用户购买了一次后就不再进行购买。而且最后一次购买的用户数量也在随时间递增,消费呈现流失上升的状况。
4、从整体消费记录来看,有一半的用户,只消费了一次。从每月新用户占比来看,1997年1月新用户占比高达90%以上,后续有所下降,1997年4月到1998年6月维持在81%左右,1998年6月以后无新用户。
5、从RFM模型来看,在8种客户中,重要保持客户的消费频次和消费金额最高,人数排在第二位;而一般发展客户消费频次和消费金额排第二位,人数却是最多。
6、从用户分层情况来看,新用户从第4月份以后没有新增;活跃用户有所下降;回流用户数量趋于稳定,每月1000多。流失/不活跃用户,数量非常多,基本上每月都在20000以上。
7、用户购买周期方面,平均购买周期是68天,最小值0天,最大值533天。绝大部分用户的购买周期都低于100天。
8、用户生命周期方面,由于只购买一次的用户(生命周期为0天)占了接近一半,排除这部分用户的影响之后,用户平均生命周期276天,中位数302天。
9、复购率和回购率方面,复购率稳定在20%左右,回购率稳定在30%左右,前3个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率和回购率都比较低。

你可能感兴趣的:(单车案例分析)