python数据分析

库版本

库版本

详情

用户在CD网站上的消费记录。本次分析,通过这份数据分析用户的消费情况以及趋势,个体消费情况,以及回购率和复购率。

导入数据

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#显示图形(自动生成画布,只在jupyter notebook中有效)
%matplotlib inline 
columns=['user_id','order_dt','order_products','order_amount']
df=pd.read_table(r'C:/Users/12585/Desktop/CDNOW_master.txt',names=columns,sep='\s+')
  • user_id:用户ID
  • order_dt:购买日期
  • order_prodects:购买产品数
  • order_amount:购买金额

查询df内容

df内容

各种统计数据

df.describe()
统计数据

其中,count代表总共有多少数据,mean代表平均值,std代表标准差,min代表最小值,max代表最大值。

观察到,order_dt中日期处理成pandas中可以计算的日期格式,如下:

df['order_dt']=pd.to_datetime(df.order_dt,format='%Y%m%d')
#新增一个字段,将order_dt.values的日期转化成当月的第一天
df['month']=df.order_dt.values.astype('datetime64[M]')

再次查询此时df内容


df内容

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

  • 每月的消费总金额
  • 每月的消费次数
  • 每月的产品购买量
  • 每月的消费人数

每月的消费总金额

# 按月归类
grouped_month=df.groupby('month')
#每个月消费金额
order_month_amount=grouped_month.order_amount.sum()
#显示部分数据
order_month_amount.head()
消费总金额
#图形采用折线的方式
plt.style.use('ggplot')
#绘制order_month_amount数据的折线图,横轴代表月份,纵轴代表每个月的总金额
order_month_amount.plot()
月销售额趋势图

说明:1997年年初的两个月作用销量陡增,接着断崖式下降,再趋于平稳。但是在接下来这一年的年初却未曾出现这种情况,推测这种销售情况可能由于某种特殊的原因导致的,且不容易复现。

每月的消费次数

grouped_month.user_id.count().plot()
月消费次数

说明:用户消费次数在前两个月较多,后暴跌,从四月份开始逐渐平稳。

每月的产品购买量

grouped_month.order_products.sum().plot()
产品购买量

说明:产品购买量的趋势同消费额和用户消费次数成正相关。

每月的消费人数(去除重复消费的用户,得到每个月的用户数)

# 这里 x 其实是一个数组,是每月分组的用户id,去重后求数组的 len 长度就代表每月的用户数
df.groupby('month').user_id.apply(lambda x:len(x.drop_duplicates())).plot()
每月消费人数

和每月用户消费次数对比可知,顾客多次消费的人数不多,大多数都是一一个月来购买一次,具体什么原因导致有待后面的分析。

用户个体消费分析

即个体的消费情况分析。

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

用户消费金额,消费次数的统计特征

#按照用户分组
grouped_user=df.groupby('user_id')
#计算单个用户消费额
grouped_user.sum().describe()
用户消费统计

说明:用户金额平均数在106左右,方差std较大,说明个体用户消费金额波动比较大。订单量的平均值为7单左右,方差std为17左右,波动相对而言较小。

用户消费金额和消费次数的散点图

grouped_user.sum().plot.scatter(x='order_amount',y='order_products')
消费额和购买量的关系图

说明:从图中可知,消费次数和消费额成正相关。大部分客户消费在4000以下,购买数量在200以下。

用户消费金额的分布图

# 直方图,分为20块
grouped_user.sum().order_amount.plot.hist(bins=100)
顾客消费情况

说明:从图中可知,大部分消费额都是比较集中,除去少部分异常值。大部分的消费额都在一千以内,客户购买力较小。下面除去较少的个别客户,得到更细致的更普遍的客户消费额分布趋势。

# 直方图,分为20块,过滤
grouped_user.sum().query('order_products<100').order_amount.plot.hist(bins=20)
顾客消费情况

用户消费次数的分布图

grouped_user.sum().query('order_amount<2000').order_products.plot.hist(bins=20)
顾客购买量直方图

说明:从消费额和消费次数的离散图中可知,存在少数异常值干扰用户消费次数,所以设置一个过滤条件,从离散图中可知,消费额小于2000的状态较普遍。

用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)

# cumsum 是求累加值
user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
# 这里 reset_index() 是为了得到一个自然数的行标签,表示的就是人数,下面的图就可以看出来多少个少占多少百分比
user_cumsum.reset_index().order_amount.plot()
消费额占比

说明 :从图中可知,百分之五十的用户贡献了百分之十五的消费额,消费额前五千的消费总额占据了消费额的百分之六十。

用户消费行为

  • 用户第一次消费(首购)
  • 用户最后一次消费
  • 新老客户消费比
    -- 多少用户仅消费一次
  • 用户分层
    -- RFM模型
    -- 新、老、活跃、回流、流失
  • 用户购买周期(按订单)
    -- 用户消费周期描述
    -- 用户消费周期分布
  • 用户生命周期(按第一次和最后一次消费) -用户生命周期描述
    -- 用户生命周期分布

用户第一次消费(首购)

# 得到最小的日期,然后统计一下各个日期的个数
grouped_user.order_dt.min().value_counts().plot()
user_id

用户最后一次消费

# 得到最大的日期,然后统计一下各个日期的个数,得到最后一次消费的情况,用户流失
grouped_user.order_dt.max().value_counts().plot()
最后一次消费日期统计

新老客户消费比

首先获得第一次和最后一次消费日期。
#新老客消费比
# 得到第一次和最后yc次消费情况,如果 min、max 日期相同,说明只消费了一次
user_life=grouped_user.order_dt.agg(['min','max'])
user_life.head()
首购以及最后一次消费日期
消费一次的客户数量。
(user_life['min']=user_life['max']).value_counts()
一次消费情况

说明:一半用户只消费了一次。

用户分层

RFM模型
# 画 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['R']= -(rfm.order_dt - rfm.order_dt.max())/np.timedelta64(1,'D')
# 重命名,也就是 R:最后一次消费距今天数,F:消费总金额 ,M:消费总产品数
# R :消费时间  F:消费金额  M:消费频次
rfm.rename(columns={'order_products':"M",'order_amount':'F'},inplace=True)
rfm.head()
处理后数据

)

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']='g'
rfm.loc[~(rfm.label=='重要价值客户'),'color']='r'
rfm.plot.scatter('F','R',c=rfm.color)
消费金额和消费次数散点图
rfm.groupby('label').sum()
RFM模型
用户生命周期 新客,活跃,回流,流失(一段时间不消费,或者不活跃)
# 数据透视, 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:活跃
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
统计每月各类用户数量
# 又把null 值填充为0
purchase_stats_ct.fillna(0).T
# 绘制了一个面积图,蓝色是注册用户,一开始有后面没有用户进来
purchase_stats_ct.fillna(0).T.plot.area()
各类用户图形表示

复购率和回购率分析

复购率

  • 自然月内,购买多次的用户占比(即,购买了两次以上)

回购率

  • 曾经购买过的用户在某一时期的再次购买的占比(可能是在三个月内)
#查看每个用户每月购买次数
pivoted_counts.head(10)
消费情况
# 区分一个,和一个以上的情况,以便于计算复购率,大于1为1,等于0为NaN,其它为0
purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
消费情况处理
# 复购人数/总消费人数(不会计算nan值)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(10,4))
复购率
# 需要使用函数来判断是否回购:当月消费过的用户下个月也消费了叫做回购,这个定义可以改变
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
# 一行行的传递过去
purchase_b=df_purchase.apply(lambda x:pd.Series(purchase_back(x),index=df_purchase.columns),axis=1)
purchase_b.head()
回购情况
# 求得回购率,回购的次数处于总购买次数
(purchase_b.sum()/purchase_b.count()).plot(figsize=(10,4))
回购率

你可能感兴趣的:(python数据分析)