#TSer#
时间序列知识整理系列,持续更新中 ⛳️
赶紧后台回复"讨论"加入讨论组交流吧 🏃
在互联网普及上升、网络零售发展驱动下,电商行业发展迅猛,用户规模持续增长。在此背景下,对用户的行为分析已经不是人力所能解决的。利用数据挖掘,机器学习的方式分析行为数据可以让从业者更好的发展其业务,调整方向,增加营收。
一般场景下,用户的行为数据大多是时间序列,比如购买序列,点击序列,浏览序列等等。如何对这些数据进行分析呢,本文介绍一篇python实战,以真实阿里云天池竞赛的数据作为案例,介绍完整的分析过程。
数据类型处理
import pandas as pd
import numpy as np
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
数据加载
字段含义:
观察数据
在源数据中添加一列表示月份:astype('datetime64[M]')
df = pd.read_csv('./Data/CDNOW_master.txt',header = None,sep = '\s+',names = ['user_id','order_dt','order_product','order_amount'])
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 int64
order_product 69659 non-null int64
order_amount 69659 non-null float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB
# 将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
# 查看统计描述
df.describe()
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
# 所有用户购买商品的平均数量
# 2.410040
# 所有用户购买商品的平均花费
# 35.893648
# 在源数据中添加一列表示月份:astype('datetime64[M]')
df['month'] = df['order_dt'].astype('datetime64[M]')
df.head()
按月分析数据
用户每月花费的总金额
绘制曲线图展示
# 用户每月花费的总金额
# 分组
df.groupby(by = 'month')['order_amount'].sum()
# 绘制曲线图展示
df.groupby(by = 'month')['order_amount'].sum().plot()
# 所有用户每月的产品购买量
df.groupby(by = 'month')['order_product'].sum()
# 图
df.groupby(by = 'month')['order_product'].sum().plot()
# 所有用户每月的消费总次数
df.groupby(by = 'month')['user_id'].count()
# 统计每月的消费人数 (一人可能消费多次要去重)nunique() 表示去重后的个数
df.groupby(by = 'month')['user_id'].nunique()
用户个体消费分析
# 用户消费总金额
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)
# 各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
df.groupby(by = 'user_id').sum().query('order_amount <= 1000')['order_amount'].hist()
# 各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)
df.groupby(by = 'user_id').sum().query('order_product <= 100')['order_product'].hist()
用户消费行为分析
用户第一次消费的月份分布,和人数统计
# 用户第一次消费的月份分布,和人数统计
# 如何确定第一次消费?—— 用户消费月份的最小值,即第一次买出现的月份
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()
用户最后一次消费的时间分布,和人数统计
# 用户最后一次消费的时间分布
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()对分组的后的数据进行多种指定方式的聚合
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()
用户分层
根据价值分层,将用户分为:
使用已有的分层模型即可rfm_func
# 分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
# 使用透视表功能
rfm = df.pivot_table(index='user_id',
aggfunc={
'order_amount':'sum',
'order_product':'sum',
'order_dt':'max'
})
# 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')
# 去除无用项目
rfm.drop(labels = 'order_dt',axis = 1,inplace = True)
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)
用户的生命周期
将用户划分为活跃用户和其他用户
知识点:DataFrame的apply和applymap的区别
#统计每个用户每个月的消费次数
user_month_count = df.pivot_table(
index = 'user_id',
values = 'order_dt',
aggfunc = 'count',
columns = 'month').fillna(0)
# 统计每个用户每个月是否消费,消费记录为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月再次购买的第一个月份为该月份的回头客
#将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)
# 返回新的df叫做df_purchase_new
df_purchase_new = DataFrame(data = pivoted_status.values.tolist(),
index = df_purchase.index,
columns = df_purchase.columns)