栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

数据分析之实例三:用户消费行为数据分析(一)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据分析之实例三:用户消费行为数据分析(一)

#user_id:用户id,order_dt:购买日期,order_products:购买产品数量,order_amount:购买金额
#数据时间:1997年1月-1998年6月的行为数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
%matplotlib inline
#在行内显示
plt.style.use('ggplot')#更改绘图风格
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']#设置字体
#导入数据
columns=['user_id','order_dt','order_products','order_amount']
df=pd.read_table('cd_ma.txt',names=columns,sep='s+') #sep=s's+'代表匹配任意空格
df

#1.日期格式需要转换
#2.存在一个用户一天内购买多次

df.describe()

df['order_date']=pd.to_datetime(df['order_dt'],format='%Y%m%d')
#format='%Y%m%d'按照指定格式转成数据列,%Y代表四位的年,%m代表两位月,%d代表两位日,%y代表两位年,%h代表两位小时,%M代表两位分钟
df['month']=df['order_date'].astype('datetime64[M]')
#将order_date转化成精度为月份的数据列,astype('datetime64[M]')精度转换,转成月份进度
df.head()

 

#按照月份统计购买产品数量,消费金额,消费次数,消费人数
plt.figure(figsize=(20,15))#单位时英寸
#每月产品购买数量
plt.subplot(2,2,1)#绘制在两行两列第一个图中
df.groupby('month')['order_products'].sum().plot()#默认折线图
plt.title('每月产品购买数量')
#每月的消费金额
plt.subplot(2,2,2)#绘制在两行两列第二个图中
df.groupby('month')['order_amount'].sum().plot()#默认折线图
plt.title('每月的消费金额')
#每月消费次数
plt.subplot(2,2,3)#绘制在两行两列第三个图中
df.groupby('month')['user_id'].count().plot()#默认折线图
plt.title('月消费次数')
#每月消费人数(根据'user_id'去重统计)
plt.subplot(2,2,4)#绘制在两行两列第三个图中
df.groupby(by='month')['user_id'].apply(lambda x:len(x.drop_duplicates())).plot()
#apply(lambda x:len(x.drop_duplicates()))去重作用,然后用len()长度计算,作为人数数量的统计
plt.title('月消费次数')

#分析结果:前三个月销量非常高,后面下降然后基本趋于平稳

 

用户个体的消费分析 

#1.用户消费金额,消费次数(产品数量)描述统计
user_grouped=df.groupby(by='user_id').sum()
user_grouped.describe()
#用户数237570,每个用户平均购买7个,但是中位数只有3个,并且最大值1033个,平均值大于中位数,明显右偏

#绘制用户的产品的购买数量与消费金额的散点图
df.plot(kind='scatter',x='order_products',y='order_amount')

#用户的消费分布图
plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.xlabel('每个订单的消费金额')
df['order_amount'].plot(kind='hist',bins=50)
#bins区间分数,影响柱子的宽度,值越大柱子越细


plt.subplot(1,2,2)
plt.xlabel('每个uid购买数量')
df.groupby(by='user_id')['order_products'].sum().plot(kind='hist',bins=50)
#每个用户购买数量非常少
#总结,购买量低,价格小于50的占绝大多数

 用户的累积消费金额占比分析

#进行用户分组,取出消费金额,进行求和,排序,重置索引
user_cumsum=df.groupby(by='user_id')['order_amount'].sum().sort_values().reset_index()
user_cumsum

#每个用户消费金额累积
#举例:
#np.cumsum(a)#累加求和函数
user_cumsum['amount_cumsum']=np.cumsum(user_cumsum['order_amount'])
#金额累加求和函数
user_cumsum

 

#消费金额总值
amount_total=user_cumsum['amount_cumsum'].max()#消费总金额
user_cumsum['amount_prop']=user_cumsum.apply(lambda x:x['amount_cumsum']/amount_total,axis=1)
#前多少名客户贡献度,apply(lambda)代表遍历函数,第一个x是一行的每一个数据,axis=1是横向操作的意思
user_cumsum.tail()

user_cumsum['amount_prop'].plot()
plt.ylabel('贡献度')
plt.xlabel('用户人数',fontsize=16,color='b')
#总结分析,前20000名贡献度40%,后四千名用户贡献度60%

用户消费行为

1.用户的首购时间

#用户分组,取最小值,即为首购时间
df.groupby(by='user_id')['order_date'].min().value_counts().plot()

最后一次购买时间 

#用户分组,取最大值,即为最后时间
df.groupby(by='user_id')['order_date'].max().value_counts().plot()
#绝大部分客户最后一次消费集中在前三个月,缺乏忠诚客户。。。。。

一、RFM模型介绍
RFM是Rencency(最近一次消费)、Frequency(消费频率)、Monetary(消费金额)三个指标首字母组合,是衡量当前用户价值和进行用户分层的重要工具

(1)Rencency:最近一次消费是指客户在平台最近一次消费和当前的时间间隔,理论上R越小的客户是价值越高的客户
(2)Frequency:消费频率是指客户在固定时间内的购买次数
(3)Monetary:消费金额是指一段时间内的消费金额

二、使用RFM模型进行用户分类
(1)根据需求,获取RFM三个维度的历史数据
(2)确定RFM三个维度的中值(业务理解、整体数据中值、二八法则)
(3)根据RFM和中值,对用户进行分层

透视表

也许大多数人都有在Excel中使用数据透视表的经历,其实Pandas也提供了一个类似的功能,名为pivot_table。虽然pivot_table非常有用,但是我发现为了格式化输出我所需要的内容,经常需要记住它的使用语法。 

在本文中,我将会跟踪一个销售渠道(也称为漏斗)。基本的问题是,一些销售周期很长(可以想一下“企业软件”、“资本设备”等),而管理者想更详细地了解它一整年的情况。

典型的问题包括:

  • 本渠道收入是多少?
  • 渠道的产品是什么?
  • 谁在什么阶段有什么产品?
  • 我们年底前结束交易的可能性有多大?

很多公司将会使用CRM工具或者其他销售使用的软件来跟踪此过程。虽然他们可能拥有有效的工具对数据进行分析,但肯定有人需要将数据导出到Excel,并使用一个透视表工具来总结这些数据。

使用Pandas透视表将是一个不错的选择,应为它有以下优点:

  • 更快(一旦设置之后)
  • 自行说明(通过查看代码,你将知道它做了什么)
  • 易于生成报告或电子邮件
  • 更灵活,因为你可以定义定制的聚合函数

用户分层

1.构建rfm模型

#透视表的使用(index:相当于groupby,values:取出的数据列,aggfunc:key值必须在values中,且必须跟随有效的聚合函数)
rfm=df.pivot_table(index='user_id',
                   values=['order_products','order_amount','order_date'],
                   aggfunc={
                       'order_date':'max',#最后一次购买
                       'order_products':'sum',#购买产品总数量
                       'order_amount':'sum'  #消费总金额                    
                   })

rfm.head()

 

rfm['R']=-(rfm['order_date']-rfm['order_date'].max())/np.timedelta64(1,'D')
#每个用户最后一次购买时间-日期列中做大值,再转换成天数,精度保留1为小数
#‘/np.timedelta64(1,'D')转成天数,精度保留一位小数
rfm.rename(columns={'order_amount':'M','order_products':'F'},inplace=True)
rfm.head()

 

 

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

    
    

#rfm['R']-rfm['R'].mean()
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rmf_func,axis=1)
#lambda x的x代表某一列,第二个x代表某一列的所有值
rfm.head()

 

 新用户,活跃用户,回流用户流失分析
1.新用户的第一:第一次消费
2.活跃用户即老客户
3.不活跃的用户则是时间窗口没有消费国的老客
4.回流用户,相当于回头客的意思
5.用户回流:自主回流和人工回流

 

pivoted_counts=df.pivot_table(
                index='user_id',
                columns='month',
                values='order_dt',
                aggfunc='count'            
).fillna(0)
pivoted_counts

 

#由于浮点数不直观,并且需要转成是消费过即可,用0,1表示
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
#apply():作用dataframe数据中的整行或整列
#applymap():作用于dataframe数据中每一个元素
#apply():本身seriers函数,在df中无法使用map函数。作用于seriers中每一个元素

df_purchase.head()

 

#判断是哪种用户
def active_status(data):#data:整行数据,共18列
    status = []#负责存放18个月的状态:ureg/new/active/unactive/return/
    for i in range(18):
        if data[i] == 0:#这个月没有消费
        #本月没有消费
            if len(status)==0:#前面没有任何记录(97年1月份)
                status.append('unreg')
            else:#开始判断上一个月状态
                if status[i-1] =='unreg':#一直未消费过
                    status.append('unreg')
                else:#上个月是new/active/unactive/return/中一种,但是这个月没有消费
                    status.append('unactive')
        else:#这个月有消费
            if len(status)==0:##前面没有任何记录(97年1月份)
                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,列名df_purchase中列名
                    


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

 

 

purchase_states_ct.T.fillna(0).plot.area()#行列转换

 

 

#回流用户占比
rate=purchase_states_ct.T.fillna(0).apply(lambda x: x/x.sum(),axis=1)
plt.plot(rate['return'],label='return')
plt.plot(rate['active'],label='active')
plt.legend()

 

 

 

 

 

用户分层

1.构建rfm模型

#透视表的使用(index:相当于groupby,values:取出的数据列,aggfunc:key值必须在values中,且必须跟随有效的聚合函数)
rfm=df.pivot_table(index='user_id',
                   values=['order_products','order_amount','order_date'],
                   aggfunc={
                       'order_date':'max',#最后一次购买
                       'order_products':'sum',#购买产品总数量
                       'order_amount':'sum'  #消费总金额                    
                   })

rfm.head()

rfm['R']=-(rfm['order_date']-rfm['order_date'].max())/np.timedelta64(1,'D')
#每个用户最后一次购买时间-日期列中做大值,再转换成天数,精度保留1为小数
#‘/np.timedelta64(1,'D')转成天数,精度保留一位小数
rfm.rename(columns={'order_amount':'M','order_products':'F'},inplace=True)
rfm.head()

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

    
    

#rfm['R']-rfm['R'].mean()
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rmf_func,axis=1)
#lambda x的x代表某一列,第二个x代表某一列的所有值
rfm.head()

#客户分层可是化,散点图
for label,grouped in rfm.groupby('label'):
    #print(label,grouped)
    x=grouped['F']#每个用户购买数量
    y=grouped['R']#最近一次购买时间有最大值相差天数
    plt.scatter(x,y,label=label)
    
plt.legend()#显示图例
plt.xlabel('F')
plt.ylabel('R')

apply函数
apply函数是`pandas`里面所有函数中自由度最高的函数。该函数如下:
Dataframe.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

该函数最有用的是第一个参数,这个参数是函数,相当于C/C++的函数指针。

这个函数需要自己实现,函数的传入参数根据axis来定,比如axis = 1,就会把一行数据作为Series的数据结构传入给自己实现的函数中,我们在函数中实现对Series不同属性之间的计算,返回一个结果,则apply函数会自动遍历每一行Dataframe的数据,最后将所有结果组合成一个Series数据结构并返回。

三、lambda 特性
lambda 函数是匿名的:
所谓匿名函数,通俗地说就是没有名字的函数。lambda函数没有名字。
lambda 函数有输入和输出:
输入是传入到参数列表argument_list的值,输出是根据表达式expression计算得到的值。
lambda 函数拥有自己的命名空间:
不能访问自己参数列表之外或全局命名空间里的参数,只能完成非常简单的功能。
常见的lambda函数示例:

lambda x, y: x*y			# 函数输入是x和y,输出是它们的积x*y
lambda:None					# 函数没有输入参数,输出是None
lambda *args: sum(args)		# 输入是任意个数参数,输出是它们的和(隐性要求输入参数必须能进行算术运算)
lambda **kwargs: 1			# 输入是任意键值对参数,输出是1

四、lambda 常见用法
    由于lambda语法是固定的,其本质上只有一种用法,那就是定义一个lambda函数。
    在实际中,根据这个lambda函数应用场景的不同,可以将lambda函数的用法扩展为以下几种:

1、将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。
示例:
add = lambda x, y: x+y
相当于定义了加法函数lambda x, y: x+y,并将其赋值给变量add,这样变量add就指向了具有加法功能的函数。
这时我们如果执行add(1, 2),其输出结果就为 3。

2、将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。
示例:
 

# 为了把标准库time中的函数sleep的功能屏蔽(Mock),我们可以在程序初始化时调用:
time.sleep=lambda x: None
# 这样,在后续代码中调用time库的sleep函数将不会执行原有的功能。
# 例如:
time.sleep(3)	# 程序不会休眠 3 秒钟,而是因为lambda输出为None,所以这里结果是什么都不做

3、将lambda函数作为参数传递给其他函数。
典型的用法就是下面我们常见的几种高阶函数。


五、lambda 用法之高阶函数
map() 函数:
描述:
map() 会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
语法:
map(function, iterable, ...)
参数:
function ----> 函数
iterable ----> 一个或多个序列
返回值:
Python 2.x 版本返回的是列表
Python 3.x 版本返回的是迭代器
 

# ===========一般写法:===========
# 1、计算平方数
def square(x):
	return x ** 2

map(square, [1,2,3,4,5])	# 计算列表各个元素的平方
# 结果:
[1, 4, 9, 16, 25]

# ===========匿名函数写法:============
# 2、计算平方数,lambda 写法
map(lambda x: x ** 2, [1, 2, 3, 4, 5])
# 结果:
[1, 4, 9, 16, 25]	 

# 3、提供两个列表,将其相同索引位置的列表元素进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
# 结果:
[3, 7, 11, 15, 19]

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/283859.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号