前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动手实战 | 用户行为数据分析

动手实战 | 用户行为数据分析

作者头像
VachelHu
发布2021-10-09 11:10:58
1.1K0
发布2021-10-09 11:10:58
举报
文章被收录于专栏:时序人时序人

#TSer#

时间序列知识整理系列,持续更新中 ⛳️

赶紧后台回复"讨论"加入讨论组交流吧 🏃

在互联网普及上升、网络零售发展驱动下,电商行业发展迅猛,用户规模持续增长。在此背景下,对用户的行为分析已经不是人力所能解决的。利用数据挖掘,机器学习的方式分析行为数据可以让从业者更好的发展其业务,调整方向,增加营收。

一般场景下,用户的行为数据大多是时间序列,比如购买序列,点击序列,浏览序列等等。如何对这些数据进行分析呢,本文介绍一篇python实战,以真实阿里云天池竞赛的数据作为案例,介绍完整的分析过程。

数据类型处理

代码语言:javascript
复制
import pandas as pd 
import numpy as np
from pandas import DataFrame,Series
import matplotlib.pyplot as plt

数据加载

字段含义:

  • user_id:用户ID
  • order_dt:购买日期
  • order_product:购买产品的数量
  • order_amount:购买金额

观察数据

  • 查看数据的数据类型
  • 数据中是否存储在缺失值
  • 将order_dt转换成时间类型
  • 查看数据的统计描述
    • 计算所有用户购买商品的平均数量
    • 计算所有用户购买商品的平均花费

在源数据中添加一列表示月份:astype('datetime64[M]')

代码语言:javascript
复制
df = pd.read_csv('./Data/CDNOW_master.txt',header = None,sep = '\s+',names = ['user_id','order_dt','order_product','order_amount'])
代码语言:javascript
复制
df.info()
代码语言:javascript
复制
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id          69659 non-null int64
order_dt         69659 non-null int64
order_product    69659 non-null int64
order_amount     69659 non-null float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB
代码语言:javascript
复制

# 将order_dt  转为时间格式
df['order_dt'] = pd.to_datetime(df['order_dt'],format = '%Y%m%d')
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id          69659 non-null int64
order_dt         69659 non-null datetime64[ns]
order_product    69659 non-null int64
order_amount     69659 non-null float64
dtypes: datetime64[ns](1), float64(1), int64(2)
memory usage: 2.1 MB
代码语言:javascript
复制

# 查看统计描述
df.describe()
代码语言:javascript
复制
user_id	order_product	order_amount
count	69659.000000	69659.000000	69659.000000
mean	11470.854592	2.410040	35.893648
std	6819.904848	2.333924	36.281942
min	1.000000	1.000000	0.000000
25%	5506.000000	1.000000	14.490000
50%	11410.000000	2.000000	25.980000
75%	17273.000000	3.000000	43.700000
max	23570.000000	99.000000	1286.010000
代码语言:javascript
复制
# 所有用户购买商品的平均数量
# 2.410040
# 所有用户购买商品的平均花费
# 35.893648
# 在源数据中添加一列表示月份:astype('datetime64[M]')
df['month'] = df['order_dt'].astype('datetime64[M]')
df.head()

按月分析数据

用户每月花费的总金额

绘制曲线图展示

  • 所有用户每月的产品购买量
  • 所有用户每月的消费总次数
  • 统计每月的消费人数
代码语言:javascript
复制
# 用户每月花费的总金额
# 分组
df.groupby(by = 'month')['order_amount'].sum()

# 绘制曲线图展示
df.groupby(by = 'month')['order_amount'].sum().plot()
代码语言:javascript
复制
# 所有用户每月的产品购买量
df.groupby(by = 'month')['order_product'].sum()
# 图
df.groupby(by = 'month')['order_product'].sum().plot()
代码语言:javascript
复制
# 所有用户每月的消费总次数
df.groupby(by = 'month')['user_id'].count()

# 统计每月的消费人数 (一人可能消费多次要去重)nunique() 表示去重后的个数
df.groupby(by = 'month')['user_id'].nunique()

用户个体消费分析

  • 用户消费总金额和消费总次数的统计描述
  • 用户消费金额和消费产品数量的散点图
  • 各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
  • 各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)
代码语言:javascript
复制
# 用户消费总金额
df.groupby(by = 'user_id')['order_amount'].sum()

# 用户消费消费总次数
df.groupby(by = 'user_id')['order_product'].sum()

# 用户消费金额和消费产品数量的散点图
user_amount_sum = df.groupby(by = 'user_id')['order_amount'].sum()
user_product_sum = df.groupby(by = 'user_id')['order_product'].sum()
plt.scatter(user_amount_sum,user_product_sum)
代码语言:javascript
复制
# 各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
df.groupby(by = 'user_id').sum().query('order_amount <= 1000')['order_amount'].hist()
代码语言:javascript
复制
# 各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)
df.groupby(by = 'user_id').sum().query('order_product <= 100')['order_product'].hist()

用户消费行为分析

用户第一次消费的月份分布,和人数统计

  • 绘制线形图
代码语言:javascript
复制
# 用户第一次消费的月份分布,和人数统计
# 如何确定第一次消费?—— 用户消费月份的最小值,即第一次买出现的月份
df.groupby(by = 'user_id')['month'].min()


# 人数统计
df.groupby(by='user_id')['month'].min().value_counts()


# 绘制线形图
df.groupby(by='user_id')['month'].min().value_counts().plot()

用户最后一次消费的时间分布,和人数统计

  • 绘制线形图
代码语言:javascript
复制
# 用户最后一次消费的时间分布
df.groupby(by='user_id')['month'].max()


# 人数统计
df.groupby(by='user_id')['month'].max().value_counts()


# 折线图
df.groupby(by='user_id')['month'].max().value_counts().plot()

新老客户的占比

  • 消费一次为新用户
  • 消费多次为老用户
  • 分析出每一个用户的第一个消费和最后一次消费的时间
    • agg(['func1','func2']):对分组后的结果进行指定聚合
  • 分析出新老客户的消费比例
代码语言:javascript
复制
# 如何判断新老用户?
# 可以通过判断用户购买时间,第一次购买和最后一次购买的时间一样则是新用户,否则是老用户
# 使用agg()对分组的后的数据进行多种指定方式的聚合
new_old_df = df.groupby(by = 'user_id')['order_dt'].agg(['min','max'])
# 判断新老用户
new_old_df['min'] == new_old_df['max'] # True 是新用户,False是老用户
# 分析占比
(new_old_df['min'] == new_old_df['max']).value_counts()

用户分层

  • 分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
  • RFM模型设计
    • R表示客户最近一次交易时间的间隔。
      • /np.timedelta64(1,'D'):去除days
  • F表示客户购买商品的总数量,F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
  • M表示客户交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。
  • 将R,F,M作用到rfm表中

根据价值分层,将用户分为:

  • 重要价值客户
  • 重要保持客户
  • 重要挽留客户
  • 重要发展客户
  • 一般价值客户
  • 一般保持客户
  • 一般挽留客户
  • 一般发展客户

使用已有的分层模型即可rfm_func

代码语言:javascript
复制
代码语言:javascript
复制
# 分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
# 使用透视表功能
rfm = df.pivot_table(index='user_id',
               aggfunc={
                   'order_amount':'sum',
                   'order_product':'sum',
                   'order_dt':'max'
               })
代码语言:javascript
复制
# R 表示用户最近一次购买商品的时间间隔
# 今天减去最后一次购买的时间
max_dt = df['order_dt'].max() # 今天
(max_dt - df.groupby('user_id')['order_dt'].max())
# 分给R
rfm['R'] = (max_dt - df.groupby('user_id')['order_dt'].max())/np.timedelta64(1,'D')
代码语言:javascript
复制
# 去除无用项目
rfm.drop(labels = 'order_dt',axis = 1,inplace = True)
代码语言:javascript
复制
def rfm_func(x):
    # 储存三个字符串的1或0
    level = x.map(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['label'] = rfm.apply(lambda x:x - x.mean()).apply(rfm_func,axis = 1)

用户的生命周期

将用户划分为活跃用户和其他用户

  • 统计每个用户每个月的消费次数
  • 统计每个用户每个月是否消费,消费记录为1否则记录为0

知识点:DataFrame的apply和applymap的区别

  • applymap:返回df
  • 将函数做用于DataFrame中的所有元素(elements)
  • apply:返回Series
  • apply()将一个函数作用于DataFrame中的每个行或者列
代码语言:javascript
复制
#统计每个用户每个月的消费次数
user_month_count = df.pivot_table(
    index = 'user_id',
    values = 'order_dt',
    aggfunc = 'count',
    columns = 'month').fillna(0)
代码语言:javascript
复制
# 统计每个用户每个月是否消费,消费记录为1否则记录为0
# 知识点:DataFrame的apply和applymap的区别
# applymap:返回df
# 将函数做用于DataFrame中的所有元素(elements)
# apply:返回Series
# apply()将一个函数作用于DataFrame中的每个行或者列
df_purchase = user_month_count.applymap(lambda x:1 if x>=1 else 0)

将用户按照每一个月份分成:

  • unreg:观望用户(前两月没买,第三个月才第一次买,则用户前两个月为观望用户)
  • unactive:首月购买后,后序月份没有购买则在没有购买的月份中该用户的为非活跃用户
  • new:当前月就进行首次购买的用户在当前月为新用户
  • active:连续月份购买的用户在这些月中为活跃用户
  • return:购买之后间隔n月再次购买的第一个月份为该月份的回头客
代码语言:javascript
复制
# 将用户按照每一个月份分成:
# unreg:观望用户(前两月没买,第三个月才第一次买,则用户前两个月为观望用户)
# unactive:首月购买后,后序月份没有购买则在没有购买的月份中该用户的为非活跃用户
# new:当前月就进行首次购买的用户在当前月为新用户
# active:连续月份购买的用户在这些月中为活跃用户
# return:购买之后间隔n月再次购买的第一个月份为该月份的回头客
#将df_purchase中的原始数据0和1修改为new,unactive......,返回新的df叫做df_purchase_new
#固定算法
def active_status(data):
    status = []#某个用户每一个月的活跃度
    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

pivoted_status = df_purchase.apply(active_status,axis = 1)
代码语言:javascript
复制
# 返回新的df叫做df_purchase_new
df_purchase_new = DataFrame(data = pivoted_status.values.tolist(),
                           index = df_purchase.index,
                           columns = df_purchase.columns)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 时序人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档