项目介绍
数据集内容为某游戏82万条玩家信息,其中包含108个字段,现需要展开数据内容对用户进行分析
项目过程
- 数据处理(包含字段清洗去重、筛选字段等)
- 新增用户分析(从玩家数量、付费玩家占比、每日新增玩家数展开分析)
- 玩家活跃度分析(从不同用户在线时长、分布特征展开分析)
- 玩家付费情况分析(从PUR,ARPPU,ARPU等关键指标得出的情况来展开分析)
- 付费玩家习惯分析(从不同玩家的pvp、pve这两个指标得出的情况来展开分析)
0. 模块导入
import pandas as pd
import numpy as np
import sqlalchemy
import matplotlib.pyplot as plt
# pyecharts 绘图包
import pyecharts.options as opts
from pyecharts.charts import Bar, Line, Boxplot, Pie
- pyecharts 绘图包版本为1.7.1
可以通过pip install pyecharts==1.7.1进行安装
1. 数据处理
# 数据大小
data.shape
# 判断空值数量
data.isnull().sum().sum()
# 判断重复值
data.drop_duplicates("user_id").shape
输出结果
(828934, 108)
0
(828934, 108)
数据有828934条,无空值、无重复值,比较干净
但该数据集有108条字段,目前对于分析暂时没用,仅提取以下字段:
- user_id : 玩家ID
- pay_price:付费金额
- register_time:玩家注册时间
- avg_online_minutes:在线时长
- pvp_battle_count:玩家PVP次数
- pvp_lanch_count:主动发起的PVP次数
- pvp_win_count:PVP胜利次数
- pve_battle_count:pve次数
- pve_lanch_count:主动PVE次数
- pve_win_count:pve胜利次数
data = data[["user_id","pay_price","register_time","avg_online_minutes","pvp_battle_count","pvp_lanch_count","pvp_win_count","pve_battle_count","pve_lanch_count","pve_win_count"]]
因为从sql数据库提取的字段,全部都为object格式,现对其进行转换
# 转换pry_price数据类型为float
data = data.astype({"pay_price":"float","avg_online_minutes":"float"})
data.loc[:,"avg_online_minutes":] = data.loc[:,"avg_online_minutes":].astype("float")
最终数据如下:
2. 新增用户分析
2.1 玩家数量
# 新增玩家数
new_all = data.user_id.count()
# 新增付费玩家数
new_pay = data.query("pay_price > 0").user_id.count()
# 付费玩家占比
new_pay / new_all
out:
- 新增玩家数量:82,8934
- 新增付费玩家:19,549
- 付费玩家占比:0.02358
# pyecharts绘图
a = [["非付费玩家",int(new_all-new_pay)], ["付费玩家", int(new_pay)]]
pie = (Pie()
.add("",a,label_opts = opts.LabelOpts(formatter="{b}:{d}%",is_show = True))
.set_global_opts(title_opts=opts.TitleOpts(title = "玩家占比", subtitle="对象均为近期新增玩家"),
legend_opts=opts.LegendOpts(pos_left="right"))
)
pie.render_notebook()
- 近期该游戏新增付费玩家数有19549,新增总玩家828934,付费玩家占比仅2.36%,消费率极低。
2.2 新增趋势
按日期将每日新增的玩家总数与付费玩家进行聚合
# 增加日期字段
data["register_day"] = data["register_time"].str[:11]
# 按日聚合
grouped_day = data.groupby("register_day")
# 绘制趋势图
# 日期
x = list(grouped_day.user_id.count().index)
# 新增总玩家
y1 = list(grouped_day.user_id.count().values)
# 新增付费玩家
y2 = list(data.query("pay_price > 0").groupby("register_day").user_id.count().values)
# pyecharts堆叠折线图绘制
line =(Line()
.add_xaxis(x)
.add_yaxis("每日新增总玩家数",[int(i) for i in y1])
.extend_axis( # 为line增加一个新的维度,添加次坐标轴
yaxis=opts.AxisOpts( # 增加一个y次坐标轴 (因为是yaxis = ...)
axislabel_opts=opts.LabelOpts(formatter="{value}"), interval=300,max_ = 2100)) #次坐标轴 标签为value值,间隔300,最大值2100
.set_global_opts(
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate = 45)),
yaxis_opts=opts.AxisOpts(name = "新增数(单位/人)"),
title_opts = opts.TitleOpts(title="每日新增趋势"))
)
line2 = Line().add_xaxis(x).add_yaxis("每日新增付费玩家",[int(i) for i in y2], yaxis_index=1) # 注意需要加 yaxis_index = 1 指定坐标轴维度
line.overlap(line2) # 表示将line2绘制在line上
line.render_notebook()
结果得知:
- 总体新增方面:在03月10日这天,注册玩家数达到峰值114035人,3月13日注册玩家达到次高峰63141人,正是因为这两天开展活动吸引了大量玩家,但随后总体新增玩家数量都维持在4-5万之间与活动前差别不大,且有轻微下降趋势,可见这两次的活动并没有带来实质性的帮助,在这方面可能需要推出持续性刺激注册的活动或加加大活动力度。
- 新增付费玩家:开展3月16日刺激充值活动,当天新增付费玩家数达到最高1703人,之前每日新增付费玩家数在900-1250之间,活动过后区间在1220-1412之间有所好转,但数据记录的最后一天新增付费玩家仅有1091人,推测可能是当天人数没有统计完成,所以暂不考虑,现在姑且认为刺激充值的活动有效。
3. 玩家活跃度分析
3.1 玩家时长对比
1. 对比全体玩家和付费玩家的平均游戏时长
all_avg_minutes = data.avg_online_minutes.mean()
pay_avg_minutes = data.query("pay_price > 0").avg_online_minutes.mean()
print("全部玩家平均在线时长:",all_avg_minutes)
print("付费玩家平均在线时长:",pay_avg_minutes)
# 绘图
bar = (
Bar()
.add_xaxis(["全体玩家","付费玩家"])
.add_yaxis("",['%.2f'% i for i in [all_avg_minutes,pay_avg_minutes]])
.set_global_opts(
title_opts=opts.TitleOpts(title="玩家平均在线时长对比"),
yaxis_opts=opts.AxisOpts(name = "时长(单位/分钟)"))
.set_series_opts(label_opts=opts.LabelOpts(is_show=True,formatter = "{c}分钟"))
)
bar.render_notebook()
#绘制箱线图
value = [list(data.avg_online_minutes),list(data.query("pay_price > 0").avg_online_minutes)]
c = Boxplot()
c.add_xaxis(["全体玩家", "付费玩家"])
c.add_yaxis("", c.prepare_data(value))
c.set_global_opts(title_opts=opts.TitleOpts(title="全体玩家与付费玩家在线时长对比"))
c.render_notebook()
直方图结果:
- 付费玩家的平均时长远远超过全体玩家的平均时长达到了135.87分钟
箱线图结果:
- 全体玩家上四分位数为5,下四分位数为0.5,平均值为1.67,最大值却达到了1065,全体玩家的流失都比较高,超过75%的玩家在线时间仅5分钟以内
- 付费玩家上四分位数为191,下四分位数为30,平均值为84.5,最大值为1081,付费玩家的平均在线时长相对来对比较高,超过75%的玩家在线时长达到了30分钟
2. 绘制在线时长分布直方图
plt.figure(figsize=(16,6))
plt.rcParams['font.size']=14
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
# 全体玩家分布 # 去掉极值影响 取时长小于400分钟的
plt.subplot(1,2,1)
data.query("avg_online_minutes < 400").avg_online_minutes.plot(kind='hist',alpha=0.7,bins = 20)
plt.title("全体玩家")
plt.ylabel("频数",fontsize = 16)
# 付费玩家分布
plt.subplot(1,2,2)
data.query("pay_price > 0").avg_online_minutes.plot(kind='hist',alpha=0.7,bins = 20)
plt.title("付费玩家")
plt.ylabel("频数",fontsize = 16)
plt.suptitle("玩家游戏时长分布直方图", fontsize = 22)
plt.show()
- 大部分玩家的游戏时长很短,仅仅有几分钟,可见玩家流失的情况时比较严重的
- 付费玩家虽然游戏时长较高,但也大部分集中在100分钟以内
3.2 游戏时长与消费金额散点分布
plt.scatter(data.query("pay_price > 0").avg_online_minutes,data.query("pay_price > 0").pay_price)
plt.xlabel("游戏时长(单位:分钟)")
plt.ylabel("充值金额(单位:元)")
plt.title("游戏时长与充值金额散点图")
plt.show()
- 游戏在线时长与充值金额分布图中,整体玩家的充值金额均在1000元以内,最高充值金额接近1.5w,但他们的游戏时长分布在0-1000分钟占比都比较均匀,由此可见,游戏在线时长与充值金额相关性并不高
4. 玩家付费情况分析
关键指标
- AU:活跃用户,这里将游戏时长达15分钟的定为活跃用户
- PU:付费用户
- APA:活跃付费用户
- ARPU:平均每个活跃用户的收入,总收入/AU
- ARPPU:平均每个活跃付费用户收入,总收入/APA
- PUR:付费比率,APA / AU
4.1 指标计算
# 总收入
GMV = data.pay_price.sum()
# 活跃用户
AU = data.query("avg_online_minutes >= 15").user_id.count()
# 活跃付费用户
APA = data.query("avg_online_minutes >= 15 and pay_price > 0").user_id.count()
# 每个活跃玩家的收入
ARPU = GMV / AU
# 每个活跃付费玩家收入
ARPPU = GMV / APA
# 付费率
PUR = APA / AU
# 活跃用户占比
AU/data.user_id.count()
plt.figure(figsize=(16,6))
# AU 和 APA 对比
plt.subplot(1,2,1)
plt.bar(["AU", "APA"],[AU, APA])
plt.title("AU 和 APA 对比")
# 付费玩家分布
plt.subplot(1,2,2)
plt.bar(["ARPU", "ARPPU"],[ARPU, ARPPU])
plt.title("ARPU 和 ARPPU 对比")
plt.show()
from pyecharts.charts import Gauge
gauge = (
Gauge(init_opts=opts.InitOpts(width="900px", height="400px"))
.add("", data_pair=[["玩家付费率:PUR", round(PUR*100,2)]])
.set_global_opts(
legend_opts=opts.LegendOpts(is_show=False),
tooltip_opts=opts.TooltipOpts(is_show=True, formatter="{c}%"),
)
)
gauge.render_notebook()
- 总玩家数有82万,但活跃用户仅有10w,占比12%左右
- 付费玩家仅有不到2w人,活跃用户付费率为16.9%,活跃付费玩家较少,说明游戏的收入表现较差
- 通过ARPU和ARPPU对比,活跃玩家人均收入仅有5元,但活跃付费玩家人均收入有32元,说明活跃付费玩家的付费能力较强,针对这一点,我们可以做一些付费功能调整和优化,可以针对大R玩家进行针对性服务。
注意:大R玩家,可以表示为游戏充值金额非常大的人,需要重点维持。
5. 玩家游戏习惯分析
先从数据表中将AU玩家与APA玩家进行筛选
au_data = data.query("avg_online_minutes >= 15")
apa_data = data.query("avg_online_minutes >= 15 and pay_price > 0")
计算AU、APA玩家的PVP情况
# AU 玩家平均PVP次数
au_data.pvp_battle_count.mean()
# AU 玩家主动发起的概率
au_data.pvp_lanch_count.sum() / au_data.pvp_battle_count.sum()
# AU 玩家胜率
au_data.pvp_win_count.sum() / au_data.pvp_battle_count.sum()
# APA 玩家平均的PVP次数
apa_data.pvp_battle_count.mean()
# AU 玩家主动发起的概率
apa_data.pvp_lanch_count.sum() / apa_data.pvp_battle_count.sum()
# AU 玩家胜率
apa_data.pvp_win_count.sum() / apa_data.pvp_battle_count.sum()
# 制作DataFrame
d = [[15.16, 0.5688, 0.5322],[27.3, 0.6553, 0.6872]]
pvp_data = pd.DataFrame(d,index = {"AU","APA"},columns = {"次数","主动发起概率","胜率"})
计算AU、APA玩家的PVE情况
# AU 玩家平均PVE次数
au_data.pve_battle_count.mean()
# AU 玩家主动发起的概率
au_data.pve_lanch_count.sum() / au_data.pve_battle_count.sum()
# AU 玩家胜率
au_data.pve_win_count.sum() / au_data.pve_battle_count.sum()
# APA 玩家平均的PVE次数
apa_data.pve_battle_count.mean()
# AU 玩家主动发起的概率
apa_data.pve_lanch_count.sum() / apa_data.pve_battle_count.sum()
# AU 玩家胜率
apa_data.pve_win_count.sum() / apa_data.pve_battle_count.sum()
# DataFrame
d = [[28.15, 0.9967, 0.9041],[51.96, 0.9957, 0.911]]
pve_data = pd.DataFrame(d,index = {"AU","APA"},columns = {"次数","主动发起概率","胜率"})
绘制pyecharts图形
bar = (Bar()
.add_xaxis(["平均PVP次数","平均PVE次数"])
.add_yaxis("AU玩家",[pvp_data.iloc[1][0],pve_data.iloc[1][0]])
.add_yaxis("APA玩家",[pvp_data.iloc[0][0],pve_data.iloc[0][0]])
.set_global_opts(
title_opts=opts.TitleOpts(title="AU、APA玩家PVP、PVE对比"),
yaxis_opts=opts.AxisOpts(name = "次数"),
legend_opts=opts.LegendOpts(pos_left="right"))
)
bar.render_notebook()
- 从上图可以看出,APA玩家的平均PVE和PVP次数都要高于AU玩家两倍左右,显然APA玩家更愿意花费更多的时间在这个游戏上。
bar = (Bar()
.add_xaxis(["主动PVP概率","PVP胜率","主动PVE概率","PVE胜率"])
.add_yaxis("AU玩家",[pvp_data.iloc[1][1],pvp_data.iloc[1][2],pve_data.iloc[1][1],pve_data.iloc[1][2]])
.add_yaxis("APA玩家",[pvp_data.iloc[0][1],pvp_data.iloc[0][2],pve_data.iloc[0][1],pve_data.iloc[0][2]])
.set_global_opts(
title_opts=opts.TitleOpts(title="AU、APA玩家PVP、PVE对比"),
yaxis_opts=opts.AxisOpts(name = "概率"),
legend_opts=opts.LegendOpts(pos_left="right"))
)
bar.render_notebook()
- 在PVE活动中,APA玩家主动发起进攻的概率和胜利的概率与AU玩家基本持平,其中主动发起PVE的概率非常高,可见游戏玩家还是比较熟悉游戏规则,基本上能主动刷副本打怪获取资源或者等级的提升。另外游戏的PVE难度也不高,玩家的PVE胜率高达90%,可见游戏体验较为友好
在PVP活动中,APA玩家主动发起进攻的概率和胜利的概率要明显高于AU玩家,在享受游戏对战乐趣的过程中,往往更能够收获胜利。
结论
1.新增用户分析
- 新增玩家有828934人,其中付费玩家有19549人,付费人数占注册总人数的2.36%。
- 每日新增玩家在3月10日有一次大高锋增长,在3月13日有一次小高峰增长。推断可能是举办了游戏活动,但是活动一过,后续新用户注册量并没有显著提升,可见这两次活动并没有给游戏的人气带来实质性的帮助。
- 在这两次活动举办期间,每日新增付费用户并没有提升,反而趋于下降,可见这两次活动主要是为了提高游戏热度。
- 建议加大活动力度,并保持一定的时间维度,给玩家充分了解游戏的时间,才能持续提高游戏热度。
2.玩家活跃度分析
- 全部玩家平均在线时长11.74分钟,付费玩家平均在线时长135.87分钟,付费玩家的平均在线时长要远远大于全体玩家的平均值,活跃度比他们大得多。
- 75%的玩家平均在线时长不超过1分钟,可见玩家流失的情况还是比较严重的。
- 付费用户中,75%以上的的用户在线时长都超过了30分钟,说明付费用户更加愿意投入时间到该款游戏中
3.玩家付费情况分析
- 付费率PUR比较低,只有2.70%。其实只要简单地开展一个首充活动,比如充1元可获得价值60元的大礼包,就能很好地提高游戏的付费率了。付费率高,一样可以得到渠道青睐,获得更多推荐展示机会(行业俗称为“吸量”),间接提高游戏的热度。
- 目前较好的手游每日ARPU超过5元;一般的手游ARPU在3~5元之间;ARPU低于3元则说明表现较差。该手游平均每用户收入ARPU很低,说明游戏的收入表现较差,但是平均每付费用户收入ARPPU很高,说明大R的付费能力强,针对这一点,我们可以做一些付费功能的调整和优化,甚至专属大R的客服,让付费用户玩的更开心。
4.付费玩家习惯分析
- APA玩家的平均PVE和PVP次数都要高于AU玩家两倍左右,显然APA玩家更愿意花费更多的时间在这个游戏上
- 在PVP活动中,APA玩家主动发起进攻的概率和胜利的概率要明显高于AU玩家,在享受游戏对战乐趣的过程中,往往更能够收获胜利。
- 在PVE活动中,APA玩家主动发起进攻的概率和胜利的概率与AU玩家基本持平,其中主动发起PVE的概率非常高,可见游戏玩家还是比较熟悉游戏规则,基本上能主动刷副本打怪获取资源或者等级的提升。
- 游戏的PVE难度也不高,玩家的PVE胜率高达90%,可见游戏体验较为友好