用户旅游数据分析(源码自用)

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
# 1.初识数据
df = pd.read_csv('kelu.csv')
# 平均分92,结合1/2分位数,大多数用户评分在100,16~19年票价都是110
# 2.分析数据
# a1.每天销量分析
df['time'] = pd.to_datetime(df['time'], format='%Y/%m/%d')
df.groupby('time')['rating'].count().plot(figsize=(12, 4))

整体来看每日销量呈现上升趋势,但是在18年5月份前后(2,3,4)出现一次较大的波动,销量急剧下滑,猜测外部因素导致
16年9月~17年1月,销量非常低,每天平均2-3张门票,猜测营业前期,知名度小
# a2.每月销量分析
df['month'] = df['time'].values.astype('datetime64[M]') # 保留月份精度的日期
df.groupby('month').count()['rating'].plot(figsize=(12, 4))
plt.xlabel('月份')
plt.ylabel('销售数量')
plt.title('16~19每月销量分析')

月份整体销量依然呈现上升趋势,但是在18年2,3,4月份销量下滑明显,可能有外部原因
a3.每个用户的购买量和消费金额分析
merge用法,相当于sql当中join
suffixes:如果两个表中有多个相同列,用suffixes给的值进行区分(默认值xy)
# 按照游客分组,统计每个游客的购买次数
grouped_count_author = df.groupby('author')['frequency'].count().reset_index()
# 按照游客分组,统计每个游客的消费金额
grouped_sum_amount = df.groupby('author')['amount'].sum().reset_index()
user_purchase_retention = pd.merge(left=grouped_count_author,
right=grouped_sum_amount,
on='author',
how='inner')
user_purchase_retention.plot.scatter(x='frequency', y='amount', figsize=(12, 4))
plt.title('用户的购买次数和消费金额关系图')
plt.xlabel('购物次数')
plt.ylabel('消费次数')
# 结论:斜率就是门票价格110,用户的消费金额和消费次数呈现线性关系

# b1.用户购买门票数量分析
df.groupby('author')['frequency'].count().plot.hist(bins=50)
plt.xlim(1, 17)
plt.xlabel('购买数量')
plt.ylabel('人数')
plt.title('用户购买门票数量直方图')
# 绝大多数用户购买过1张门票,用户在7000人次左右,少数人购买过2~4张门票
# b2.用户购买门票2次及以上情况分析
df_frequency_2 = df.groupby('author').count().reset_index()
df_frequency_2[df_frequency_2['frequency'] >= 2].groupby('author')['frequency'].sum().plot.hist(bins=50)
plt.xlabel('购买数量')
plt.ylabel('人数')
plt.title('购买门票在2次及以上的用户数量')
# 消费两次的用户在整体上占比较大,大于2次的用户占小部分,用户购买次数最多为8次

# b3.查看购买2次及以上的具体人数
df_frequency_2[df_frequency_2['frequency'] >= 2].groupby('frequency')['author'].count()
# 除去购买一次的顾客,可以看出购买2次有402人,购买3次的99人,以此类推得知大多数数据倾向于购买2~5
# b4.购买次数在1~5次之间的用户占比分析
# 对用户author进行分组 取出消费频率 进行逻辑判断(1-5) 数据可视化(pie)
df_frequency_gte_1 = df.groupby('author')['frequency'].count().reset_index()
# 购买次数>=1
df_frequency_gte_1 = df_frequency_gte_1[df_frequency_gte_1['frequency'] >= 1]
# 购买次数<=5
values = df_frequency_gte_1[df_frequency_gte_1['frequency'] <= 5].groupby('frequency')['frequency'].count()
# 绘制饼图
labels = ['1次', '2次', '3次', '4次', '5次']
plt.pie(values, labels=labels, autopct='%1.1f%%')
plt.title('购买次数在1~5次之间的用户占比')
plt.legend()
plt.show()

# b5.购买次数在2~5次之间的用户占比分析
df_frequency_gte_2 = df.groupby('author')['frequency'].count().reset_index()
# 购买次数>=1
df_frequency_gte_2 = df_frequency_gte_2[df_frequency_gte_2['frequency'] >= 2]
# 购买次数<=5
values = df_frequency_gte_2[df_frequency_gte_2['frequency'] <= 5].groupby('frequency')['frequency'].count()
# 绘制饼图
labels = ['2次', '3次', '4次', '5次']
plt.pie(values, labels=labels, autopct='%1.1f%%')
plt.title('购买次数在2~5次之间的用户占比')
plt.legend()

# 在购物次数在2~5次的用户中,其中消费2次的占比70%,消费3次占比17%,4次占比8.5%,5次占比4.3%。消费2,3次用户依然很重要,消费次数在4,5比重较少,需要针对性的对2,3次的用户进行引导,消费次数1次的用户,可以尝试转化到消费2,3
# c1.复购率分析
pivot_count = df.pivot_table(index='author',
columns='month',
values='frequency',
aggfunc='count').fillna(0)
三种情况:
消费次数>1,为复购用户,用1表示
消费次数=1,为非复购用户,用0表示
消费次数=0,未消费用户,用nan表示
pivot_count = pivot_count.applymap(lambda x: 1 if x > 1 else np.NaN if x == 0 else 0)
(pivot_count.sum()/pivot_count.count()).plot()
plt.xlabel('时间(月)')
plt.ylabel('百分比(%)')
plt.title('16~19年每月复购率')
# 16年9月复购率最高达到7.5%,然后开始下降,趋于平稳在1.2%

# c2.复购用户人数
pivot_count.sum().plot()
plt.xlabel('时间/月')
plt.ylabel('复购人数')
plt.title('16~19年每月的复购人数折线图')
# 整体来看,复购人数呈现上升趋势,但是在18年2,3,4,10和19年2月份,复购人数下降较为明显,出现异常信号,需要和业务部门具体分析情况

# c3.回购率分析
pivot_purchase = df.pivot_table(index='author',
columns='month',
values='frequency',
aggfunc='count').fillna(0)
def purchase_return(data): # data:代表的是每一名游客的所有月份消费记录
status = [] # 存储每一个月回购状态
for i in range(30): # 遍历每一个月
# 本月消费了
if data[i] == 1:
if data[i + 1] == 1: # 1:回购用户
status.append(1)
else:
status.append(0) # 0:非回购用户(当前月消费了,下个月未消费)
else: # 本月未消费
status.append(np.NaN) # nan:当前月未消费
status.append(np.NaN) # 填充最后一列数据
return pd.Series(status, pivot_purchase.columns)
pivot_purchase_return = pivot_purchase.apply(purchase_return, axis=1)
# (pivot_purchase_return.sum()/pivot_purchase_return.count()).plot()
plt.title('16~19年每月的回购率')
plt.xlabel('月份')
plt.ylabel('回购率%')
# 回购率最高在18年6月份,达到4%;整体来看回购率呈现微弱的上升趋势,出现了几次较大下滑,分别是17-6,17-1,18-8,19-1

# c4.回购人数分析
pivot_purchase_return.sum().plot()
plt.title('16~19年每月的回购人数')
plt.xlabel('人数')
plt.ylabel('回购率%')
# 整体呈现上升趋势,回购人数最多时在18-11,人数为17人;其中有几次回购人数下降较为明显,主要在分别是17-6,18-1,18-8,19-1

# c5.每个月分层用户占比情况
def active_status(data): # data:整行数据,共18列
status = [] # 负责存储18个月的状态:unreg|new|unactive|return
for i in range(31):
# 本月没有消费==0
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') # 不管上个月是否消费过,本月都是不活跃的
# 本月有消费==1
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: # new/active/return=1
status.append('active')
return pd.Series(status, pivot_purchase.columns) # 值status,列名df_purchase中的列名
pivot_purchase_status = pivot_purchase.apply(active_status, axis=1)
pivot_status_count = pivot_purchase_status.replace('unreg', np.NaN).apply(pd.value_counts)
pivot_status_count.T.plot.area()
# 可以看出,红色(不活跃用户)占据网站用户的主体;橙色(新用户)从17-1~19-1,呈现上升趋势;但是在18-4左右,新用户的量突然急剧下降,异常信号;以后新用户又开始逐渐上涨,回复稳定状态;绿色(回流用户),一直维持稳定状态,但是在18年2~4月份,出现异常下降情况,异常信号;

# c6.每月不同用户的占比
return_rate = pivot_status_count.apply(lambda x: x/x.sum())
return_rate.T.plot()
# 在17-1过后,网站用户主体由不活跃用户组成,新用户占比开始逐渐下降,并且趋于稳定,稳定在10%左右;活跃用户和回流用户,一直很稳定,并且占比较小;16-9月前后,新用户和不活跃用户,发生较大变化,猜测由活动或节假日造成...

# c7.每月活跃用户的占比
return_rate.T['active'].plot(figsize=(12, 6))
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.title('每月活跃用户的占比分析')
# 在17-1月份活跃用户占比较高,在0.5%,但是在1~2月份,急剧下降,猜测可能是春节或气温的原因;结合历年1~2月份销量来看,都会出现一定比例的下降,验证了猜测;在18年2月和5月出现异常,门票销量下降,猜测降水或台风影响(对于公司内部情况未知,只猜测外部因素)

# c8.每月回流用户的占比分析
return_rate.T['return'].plot(figsize=(12, 6))
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.title('每月回流用户的占比分析')

整体来看,回流用户比例上升趋势,但是波动较大;在17年1月和6月,18年4月,19年2月,回流用户比例都出现了较大幅度下降,表现为异常信号;回流用户平均值在0.73%左右,在17年9月份以后,仅有两个异常点在平均值以下;在17年9月份之前,所有数据都显示出回流用户比例低于平均值,猜测景点开放不久很多游客尚未发现本景点,或者本景点在该平台刚上线不久
不论是回流用户还是活跃用户,在以上几个月份中都表现出下降趋势;
# d1.用户的生命周期
time_min = df.groupby('author')['time'].min()
time_max = df.groupby('author')['time'].max()
life_time = (time_max-time_min).reset_index()
# print(life_time.describe())
# 通过原样本8757条和count=7722得知,存在一个用户多次消费的情况;平均生命周期天数23天,通过25%,50%,75%分位数得知,绝大多数用户生命周期为0天;最大生命周期为864天
# d2.用户生命周期直方图
life_time['life_time'] = life_time['time']/np.timedelta64(1, 'D')
# life_time['life_time'].plot.hist(bins=100, figsize=(12, 6))
plt.xlabel('天数')
plt.ylabel('人数')
plt.title('所有用户的生命周期直方图')
# 生命周期为0的用户(仅在一天内有过消费,之后在没消费过),存在7130个用户;由于总用户数为7722,其余592人属于优质的忠诚客户

# d3.生命周期大于0天的客户,直方图
life_time[life_time['life_time'] > 0]['life_time'].plot.hist(bins=100, figsize=(12, 6))
plt.xlabel('天数')
plt.ylabel('人数')
plt.title('生命周期在0天以上的用户的分布直方图')
print(life_time[life_time['life_time'] > 0][life_time].mean())
# 去掉生命周期为0的客户,可知用户平均生命周期为300天,生命周期在100天的用户量达到了最大值17人,生命周期在100~350天来看,用户量呈现缓慢下降的趋势;350~800天左右来看,用户量下降速度明显,存在一定用户流失,而忠诚用户越来越少

# d4.各时间段的用户留存率
留存率:1~90天,有多少留存用户。求出用户的留存天数,比如留存天数==89,属于1~90天内的留存用户
留存天数计算方式:用户每一次的消费时间分别减去用户第一次消费时间
user_purchase_retention = pd.merge(left=df, right=time_min.reset_index(), how='inner', on='author', suffixes=('', '_min'))
# 计算留存天数
user_purchase_retention['time_diff'] = user_purchase_retention['time']-user_purchase_retention['time_min']
# 将time_diff转成数值
user_purchase_retention['time_diff'] = user_purchase_retention['time_diff'].apply(lambda x: x/np.timedelta64(1, 'D'))
# 生成时间跨度(3个月,即90天),判断属于那个区间
bins = [i*90 for i in range(11)]
user_purchase_retention['time_diff_bin'] = pd.cut(user_purchase_retention['time_diff'], bins)
# 统计每个游客,在不同的时间段内消费频率和值(便于稍后判断该用户在某个区间内是不是留存用户)
pivot_retention = user_purchase_retention.groupby(['author', 'time_diff_bin'])['frequency'].sum().unstack()
# 判断是否是留存用户(1:留存,0:未留存)
pivot_retention_trans = pivot_retention.fillna(0).applymap(lambda x: 1 if x > 0 else 0)
(pivot_retention_trans.sum()/pivot_retention_trans.count()).plot.bar()
plt.xlabel('时间跨度(天)')
plt.ylabel('留存率')
plt.title('各时间段内的用户留存率')

# 如图,每个周期是3个月,第一个周期的留存率在2.2%,前三个周期的递减速度在0.3%左右。在第四五个周期的时候趋于平稳,稳定在留存率1.5%左右;从第五个周期开始,留存率明显下降,下降到几乎0%,在第四五周期(1年)的时候,需要采取方法将用户留住进行再次消费,如果再跨度为1年的时候,不召回用户,则就会面临大量用户流失的风险