一、字段含义与业务理解
《野蛮时代》是一款SLG游戏与早年的《帝国时代》相似,为了更好的理解数据我有去体验一段时间,以下就是我对这款游戏的业务理解。
整体游戏的玩法是,你作为一个部落领袖要去建造升级自己部落的建筑如兵营、瞭望塔、要塞等,而这些建筑的升级需要木材与食物,同时还存在着一定依赖关系,比如你必须先升级要塞到7级才能升级兵营至7级。而这些建筑根据其用途可以分为这么几类:
1.战争类
兵营、士兵小屋、治疗小井、治疗之泉、瞭望塔、据点传送门,其作用分别是训练士兵、提供士兵居所、给受伤士兵提供居所、治疗受伤士兵、探测其它部落对我方发起的进攻、将士兵传送到我方据点。
2.联盟类
你作为一个部落的首领,并非形单影只还需要加入联盟,因此也需要一些联盟建筑,包括战争大厅、联盟货车、联盟大厅。其作用是分别是与联盟其它成员一起发动战争,给其它成员运送物资、给援军提供住所。
3.伙伴培养类
你不是一个人在战斗,你还可以选择召唤自己的1-5星伙伴和培养自己的巨龙。其包括的建筑有占卜台、祭坛、冒险传送门、天梯、龙秘境,作用分别是招募伙伴、强化伙伴、打怪升级、与其它玩家进行PK、培养孵化巨龙。
4.辅助类
包括的建筑有圣火、智慧神庙、幸运小屋、神秘水晶、魔法幸运树、工作间、仓库、折扣商店。其作用分别是点燃圣火增加资源生产速度、智慧神庙用来进行科技研发、幸运小屋给予每日登陆奖励、神秘水晶用来购买道具、魔法幸运物用来许愿免费获得资源、工作间用来完成每日任务和联盟任务、仓库用来保护资源和生产资源、折扣商店用来获取便宜道具。
以上就是各种建筑和其作用,但游戏本身肯定不是天天升级建筑,还需要一定给予玩家一定活动空间,而整体活动可以分为四类:
打野怪、打巨龙与资源采集,你需要派自己的部队到领土之外去击败野怪获取资源,或者是直接搜集现成资源。
进行侵略,攻击其它玩家营地来获取资源。
让自己召唤过来的伙伴进行冒险,提升伙伴星级、等级、铭文。
4.部落入侵、霜火大陆争夺战(不同服玩家进行战争),矿岛争夺战。
上面这些活动和建筑的升级与建设就形成了这个游戏的核心玩法。而游戏盈利点也从中而来,主要包括三点点:
建筑升级和训练士兵都需要时间,许多人不愿意等待,那么势必就需要付费充值,充值使我更强。
资源的获取,只有有了充足的木材、食物、魔法石等资源才能升级建筑和打造出更强的军队。
伙伴与巨龙的强化,要想获得5星伙伴,那你最好是充钱获得抽取机会。
有了以上对业务的理解,那我们再来看对应的数据就有了更深刻一些的体会,我们来从拥有的数据集中选取部分字段来进行分析,具体字段如下:
字段名 | 字段解释 | 数据时间 |
---|---|---|
user_id | 用户唯一标识 | 永久 |
register_time | 玩家注册时间 | 永久 |
meat_reduce_value | 肉消耗数量 | 前七日 |
wood_reduce_value | 木材消耗数量 | 前七日 |
stone_reduce_value | 石头消耗数量 | 前七日 |
ivory_reduce_value | 象牙消耗数量 | 前七日 |
magic_reduce_value | 魔法石消耗数量 | 前七日 |
infantry_add_value | 勇士招募数量 | 前七日 |
infantry_reduce_value | 勇士损失数量 | 前七日 |
wound_infantry_add_value | 勇士伤兵产生数量 | 前七日 |
wound_infantry_reduce_value | 勇士伤兵恢复数量 | 前七日 |
general_acceleration_reduce_value | 通用加速消耗数量 | 前七日 |
building_acceleration_reduce_value | 建筑加速消耗数量 | 前七日 |
reaserch_acceleration_reduce_value | 科研加速消耗数量 | 前七日 |
training_acceleration_reduce_value | 训练加速消耗数量 | 前七日 |
treatment_acceleration_reduce_value | 治疗加速消耗数量 | 前七日 |
pvp_battle_count | 玩家对玩家次数 | 前七日 |
pvp_lanch_count | 主动发起PVP次数 | 前七日 |
pve_battle_count | 玩家对机器次数 | 前七日 |
pvp_win_count | PVP胜利次数 | 前七日 |
pve_win_count | PVE胜利次数 | 前七日 |
avg_online_minutes | 平均在线时间 | 前七日 |
pay_price | 消费金额 | 前七日 |
pay_count | 消费次数 | 前七日 |
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#选取相应字段
select_columns=['user_id','register_time','stone_reduce_value','ivory_reduce_value','meat_reduce_value','magic_reduce_value', \
'infantry_add_value','infantry_reduce_value','wound_infantry_add_value','wound_infantry_reduce_value','general_acceleration_reduce_value' \
,'building_acceleration_reduce_value','reaserch_acceleration_reduce_value','training_acceleration_reduce_value','treatment_acceleration_reduce_value', \
'pvp_battle_count','pvp_lanch_count','pve_battle_count','pvp_win_count','pve_win_count','avg_online_minutes','pay_price','pay_count']
#数据读取
original_data=pd.read_csv(r'F:\the-craft-of-selfteaching\game_data\data.csv',usecols=select_columns)
#显示数据前五行
original_data.head()
以上代码输出如下:
二、数据清洗
- 查看空值
original_data.info()
我们能发现数据一共828934行,没有空值。
- 异常值处理
original_data.info()
我们能从图中发现没有异常值,但是有一个非常奇怪的事情就是超过25%的玩家没有进行木材和食品的消耗,没有消耗木材和食物进行建筑搭建,基于对业务的理解,这是一个极其奇怪的事情。这说明了一个问题,有极大比例用户没有完成注册与激活这一步。
- 重复值处理
#显示每一列唯一值个数
print(original_data.nunique())
我们能看到user_id唯一值个数与行数相等,说明没有重复值。
- 格式转换
由于register_time这列以日期时间格式显示,我们要把后面的日期进行去除,也就是进行格式清理。
#去除时间
original_data['register_time']=original_data['register_time'].apply(lambda x : x[0:10])
original_data['register_time'].head(5)
三、问题提出与分析
- 根据AARRR模型,用户从注册到激活,激活到留存,留存到付费,转化率如何,不同注册时间用户对应各个指标表现如何?
#不同注册时间用户对应的注册用户数量
register_number_of_everyday=original_data['register_time'].value_counts().sort_index()
#不同注册时间用户对应的激活用户数量
active_user_number_of_everyday=original_data.loc[original_data['wood_reduce_value']!=0]['register_time'].value_counts().sort_index()
#不同注册时间用户对应的留存用户数量
retention_user_number_of_everyday=original_data.loc[(original_data['wound_infantry_add_value']!=0)|(original_data['pay_count']!=0)]['register_time'].value_counts().sort_index()
#不同注册时间用户对应的付费用户数量
pay_user_number_of_everyday=original_data.loc[original_data['pay_count']!=0]['register_time'].value_counts().sort_index()
#总注册用户数量
total_register_number=original_data.shape[0]
#总激活用户数量
total_active_user_number=original_data.loc[original_data['wood_reduce_value']!=0].shape[0]
#总留存用户数量
total_retention_user_number=original_data.loc[original_data['wound_infantry_add_value']!=0].shape[0]
#总付费用户数量
total_pay_user_number=original_data.loc[original_data['pay_count']!=0].shape[0]
print('总注册用户数为:',total_register_number)
print('总激活用户数为:',total_active_user_number)
print('总留存用户数为:',total_retention_user_number)
print('总付费用户数为:',total_pay_user_number)
结果如下:
总注册用户数为: 828934
总激活用户数为: 599557
总留存用户数为: 149929
总付费用户数为: 19549
在上面我们用不同指标筛选出对应用户,在这里进行相应说明。
注册用户是指:已经注册的用户
激活用户是指:那些有消耗木材进行建筑物建造的用户;
留存用户是指:那些跟其它玩家发生冲突以至于有勇士伤兵产生的用户或者是无伤兵产生但有付费的用户,
付费用户是指:付费玩家。
光看数据我们很难有直观体会,因此我们将相应数据进行可视化。
import seaborn as sns
#我们将不同注册时间用户对应的数据进行合并
total_data_everyday=pd.concat([register_number_of_everyday,active_user_number_of_everyday,retention_user_number_of_everyday,pay_user_number_of_everyday],axis=1)
#修改列名
total_data_everyday.columns=['register','active','retention','pay']
total_data_everyday
然后我们再根据这个数据进行折线图绘制。
#构建折线图函数
def get_lineplot(title,data):
plt.figure(figsize=(25,13))
plt.xlabel('date')
all_graph=sns.lineplot( data=data)
plt.title(title,fontsize=20)
plt.show()
#先获取注册用户和激活用户的情况,因为这两个数据量级相差不大,从图像中可以看出相应趋势
get_lineplot('The number of register and active user ',total_data_everyday[['register','active']])
注册用户和激活用户折线图:
#留存用户折线图
get_lineplot('The number of retention user ',total_data_everyday['retention'])
留存用户折线图:
#付费用户折线图
get_lineplot('The number of payment user ',total_data_everyday['pay'])
付费用户折线图:
我们能从图中看到,3月10号、3月13号、3月16号、3月21号这四天从注册数量到留存数量都呈“尖峰状”,我们推测是有搞一些运营活动。然而3月10号与3月13号这两天里的用户却在付费方面表现极差,而3月16号与3月21号的用户付费意向高。所以如果只是单单想要极大增加留存用户数就应该进行3月10日与3月16日的运营活动,如果既想要高留存又要高付费,那么后两者的运营活动更为适合。
看完了不同日期对应的指标分析,我们再来看看总体情况是什么样的,并画出相应漏斗图进行分析。
from pyecharts import options as opts
from pyecharts.globals import CurrentConfig, NotebookType
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
from pyecharts.render import make_snapshot
from pyecharts.charts import Funnel
pyechart_data=[828934,599557,146013,19549] #不同阶段用户数量
labels = total_data_everyday.columns.to_list() #设置标签
def funnel_base() -> Funnel:
c = (
Funnel()
.add("转化", [list(z) for z in zip(labels,pyechart_data )])
.set_global_opts(title_opts=opts.TitleOpts(title="AARR漏斗图"))
)
return c
funnel_base().load_javascript()
funnel_base().render_notebook()
#请注意如果你跟我一样使用的是jupyter lab ,一定要将这些代码放到3个cell里分别运行,否则漏斗图显示不出来,呈现一片空白
print(f'从注册到激活转化率为: {round(599557/828934*100,2)}%')
print(f'从激活到留存转化率为: {round(149929/599557*100,2)}%')
print(f'从留存到付费转化率为: {round(19549/149929*100,2)}%')
print(f'用户付费率PR为: {round(19549/599557*100,2)}%')
从注册到激活转化率为: 72.33%
从激活到留存转化率为: 25.01%
从留存到付费转化率为: 13.04%
用户付费率PR为: 3.26%
这里的付费率是指付费用户占激活用户百分比。
我们能发现用户付费率最终为3.26%,而根据上图TalkingData发布的18年5月移动游戏数据指标来看,模拟类游戏付费率在安卓端和苹果端仅为1.74%和2.25%,所以《野蛮时代》的付费率是相当高的。而我们从漏斗图中能看到激活用户到留存用户转化率只有25%,这回我们结合avg_online_minutes平均在线时长进行分析,看看留存下来的用户与未留存下来的用户,在在线时长方面有什么差异。
- 留存用户与未留存用户在在线时长上的差别探究
#留存用户在线时长
retention_user_avg_online_time=original_data.loc[original_data['wound_infantry_add_value']!=0]['avg_online_minutes']
#未留存用户在线时长
unretention_user_avg_online_time=original_data.loc[(original_data['wood_reduce_value']!=0)&(original_data['wound_infantry_add_value']==0)]['avg_online_minutes']
#对留存用户在线时长进行描述性统计分析
retention_user_avg_online_time.describe()
#对未留存用户在线时长进行描述性统计分析
unretention_user_avg_online_time.describe()
我们能通过对比发现一点百分之75%的未留存用户平均在线时长未超过6分钟,而留存用户中则相反超过75%的留存用户平均在线时长超过6分钟。所以显而易见的一件事情是,许多玩家在还未熟悉游戏玩法时,就直接退出,所以新用户引导设计还需要进一步优化。
具体往哪方面优化呢?我这里有一个建议,在体验过游戏后我发现前几分钟所有操作都是不停根据指令建造各种建筑,玩家体验并不好,或者说根本没有自主性,为什么不可以新玩家一进入游戏那些新建筑就已全部搭建好了呢?
举个例子,新玩家一进入游戏,1级兵营就已经建造好并且手底下还有一些士兵,然后你指引玩家对野外野怪进行攻击获取资源,这样自主操作空间就大了,不至于一开始就不停点点点搭建建筑。当然具体可行性,需要进行A/B测试来验证。
除此之外,我们在上面两张图发现了三个异常值。第一个异常是留存用户中竟然有在线时长为0的人,因为我们是用有伤兵产生或者有付费行为来定义留存,而有伤兵产生就意味着玩家一定有去操作,所以我们具体来看一下数据情况。
#留存用户但在线时间为0
original_data.loc[((original_data['wound_infantry_add_value']!=0)|(original_data['pay_count']!=0))&(original_data['avg_online_minutes']==0)]
从上面两张图,我们发现玩家主动发起6次pvp但在线时长是0,这说明后端系统有漏洞,导致数据异常,在工作中需要沟通,定位问题然后去解决。
第二个异常是未留存用户中也有在线时长为零的,我们猜测也是系统出现问题导致数据异常。
#在线时间为0的未留存用户
original_data.loc[(original_data['wood_reduce_value']!=0)&(original_data['wound_infantry_add_value']==0)&(original_data['pay_count']==0)&(original_data['avg_online_minutes']==0)]
一共有288条数据有木材消耗,但无在线时长,还是系统漏洞。
第三个异常是我们发现未留存用户中有存在在线时长超过1000分钟的,我们来找到具体数据看看是异常值,还是正常值。
#在线时间大于1000分钟的未留存用户
original_data.loc[(original_data['avg_online_minutes']>1000)&(original_data['wood_reduce_value']!=0)&(original_data['wound_infantry_add_value']==0)&(original_data['pay_count']==0)]
我们发现除了user_id为2619848的用户数据异常外(因为在线时长几十个小时,但木材消耗量却只有3700),其余皆为真实用户数据,只不过这些用户既不付费也没有因为与其它玩家交战造成士兵伤亡。
- 平均用户收入、平均每付费用户收入、一次性付费用户占比
pay_user=original_data.loc[original_data['pay_price']!=0].copy()
ARPU=round(pay_user['pay_price'].sum()/original_data.shape[0],2)
ARPPU=round(pay_user['pay_price'].sum()/total_pay_user_number,2)
one_pay_user_number_rate=round(pay_user.loc[pay_user['pay_count']==1].shape[0]/pay_user.shape[0],4)
one_pay_user_total_pay_price_rate=pay_user.loc[pay_user['pay_count']==1]['pay_price'].sum()/pay_user['pay_price'].sum()
print('ARPU平均每用户收入贡献: {}'.format(ARPU))
print('ARPPU平均每付费用户收入贡献: {}'.format(ARPPU))
print('一次付费用户人数占比: {}%'.format(one_pay_rate*100))
print('一次性付费用户收入贡献占比:{}%'.format(round(one_pay_user_total_pay_price_rate*100,2)))
ARPU平均每用户收入贡献: 0.67
ARPPU平均每付费用户收入贡献: 28.49
一次付费用户人数占比: 43.04%
一次性付费用户收入贡献占比:2.38%
我们通过分析发现了一个糟糕的现象,那就是一次性付费用户占比太大,提供的收入太小,这个时候我们就应该挤掉水分,算一算有效付费率。
在这里我们定义有效付费率=付费率*(1-一次性付费用户占比),最后得到有效付费率为1.86%,高于模拟类游戏行业平均水准,还是不错的。
4.鲸鱼用户收入贡献与画像分析
在游戏行业中将付费用户分为小鱼用户、海豚用户、鲸鱼用户,鲸鱼用户是游戏运营中的重头戏,甚至会专门分析鲸鱼用户的留存率,原因在于少量的鲸鱼用户往往为游戏贡献了超过80%的收入。接下来我们来看看鲸鱼用户对收入的贡献,然后对比留存非付费用户,看看两类群体在行为上有什么差异。
我们将付费金额排在前20%的当做鲸鱼用户也就是高价值用户
#我们将付费金额排在前20%的当做鲸鱼用户也就是高价值用户
high_value_pay_user=original_data.loc[original_data['pay_price']!=0].sort_values(by='pay_price',ascending=False).head(int(19549*0.2))
#鲸鱼用户对收入贡献率
high_value_user_payrate_of_total=high_value_pay_user['pay_price'].sum()/original_data.loc[original_data['pay_price']!=0]['pay_price'].sum()
#留存下来但却不付费的用户,我们当做活跃非付费用户
active_user_not_pay=original_data.loc[(original_data['wound_infantry_add_value']!=0)&(original_data['pay_price']==0)]
print('鲸鱼用户收入贡献为:{}%'.format(round(high_value_user_payrate_of_total*100,2)))
鲸鱼用户收入贡献为:89.71%
付费用户之所以会付费主要在于充钱使我更强,而这个游戏里要想直观体会到自己比其它玩家强,那就是建筑等级还有发起PVP直接进攻其它玩家,所以我们猜测付费玩家加速道具使用频率高,同时PVP、PVE之类的指标都要比活跃非付费用户高。
pd.set_option('display.max_columns', 40)
high_value_pay_user.describe()
active_user_not_pay.describe()
上面两图每行数据的含义是数据行数、平均值、最小值、第一四分位数、中位数、第三四分位数、最大值。我们可以看到在所有加速道具的使用上高价值付费用户都全面领先。
print(f'高价值付费玩家PVP平均胜率为:{round(34.021745/43.138654*100,2)}%')
print(f'高价值付费玩家PVE平均胜率为:{round(67.859043/74.298286*100,2)}%')
print(f'活跃非付费玩家PVP平均胜率为:{round(3.890129/9.531600*100,2)}%')
print(f'活跃非付费玩家PVE平均胜率为:{round(12.149110/13.559327*100,2)}%')
高价值付费玩家PVP平均胜率为:78.87%
高价值付费玩家PVE平均胜率为:91.33%
活跃非付费玩家PVP平均胜率为:40.81%
活跃非付费玩家PVE平均胜率为:89.6%
我们能发现两类用户在PVP、PVE数量上都有显著差距,在PVE胜率上差距不大在PVP胜率上有一定差距。
玩家付费从数据来看就是他的数据到达某个阈值,然后自然而然发生的事情。综合加速道具使用和PVP、PVE情况,我们可以在前期给予这些活跃非付费用户更多加速道具培养他们使用习惯,而我们也能看到活跃非付费玩家PVP胜率只有40.81%,我们可以适度给予非付费玩家一些战争道具如伪装术使自己部队数在对方侦查时翻倍或者是12小时防御加成,来使玩家体验得以提升。此外对于那些能够巧妙避开所有付费,但同时活跃度高的玩家,我们可以挖掘其社交属性,让他把这款游戏分享给别人时得到相应道具奖励,完成AARRR模型的最后一步。
结论
- 根据AARRR模型从获取到付费每个阶段的转化率分别为72.32%,25%,13.04%,整体付费率为3.26%,与行业平均付费率1.74%相比,要高接近两倍。
- 针对不同注册时间用户进行转化率分析,发现由于运营活动3月10号与3月13号这两天里的用户在激活、留存转化方面表现优异但在付费方面表现极差,而3月16号与3月21号的用户在激活、留存、转化方面表现良好并且付费意向也高。所以要想提高留存运营活动偏前者,要想提高付费运营偏后者。
- 根据留存用户与未留存用户在线时长分析,我们发现超过75%的未留存用户在线时长不超过6分钟,而留存用户则75%以上都超过6分钟。所以我们建议在新手引导方面做出相应改善,直接跳过1级建筑建设过程,引导用户进行更有操作性的伙伴抽取、打野怪等行动。
- 通过计算我们得到ARPU平均每用户收入贡献: 0.67,ARPPU平均每付费用户收入贡献: 28.49,一次付费用户人数占比: 43.04%,一次性付费用户收入贡献占比:2.38%,所以虽然整体付费率有3.26%,但一次性付费用户占比大收入贡献小,小鱼用户过多,导致整体付费率不能真正体现游戏的收入转化机制是否设计良好,所以我们改变算法,计算出有效付费率为1.86%,高于行业平均水准。
- 我们对比鲸鱼用户与活跃非付费用户数据,发现在加速道具使用、PVP次数、PVE次数、PVP胜率上,鲸鱼用户都远高于活跃非付费用户。所以我们建议在前期多提供一些道具,培养活跃非付费用户使用习惯,这样等后面没有那么多道具赠送时,他们就会忍不住购买。至于那些肝帝,则要发挥他们的社交影响力,让他们完成分享游戏的任务,发挥自己的余热。