因为想要去腾讯实习,所以参加了今年的腾讯游戏安全技术竞赛,这个比赛赢了会有一个实习的绿色通道。选了数据分析方向里面的机器学习。
初赛题目很有趣,关于LOL(英雄联盟)的代练检测。
Moba游戏常见的5v5模式,玩家将与其余9名玩家共同组成对局。对局双方各5人,两方队伍通过优先推倒敌方水晶来取得胜利。排位赛的单双模式指:玩家可以选择自己参加排位或以双人组队的形式参加排位赛,比赛成绩都会对自己的段位产生影响。
我们提供某款Moba游戏在2019.03.07当天部分玩家账号,训练集名单已经标注了是否代练账号,未标注的10000个账号作为测试集,同时我们提供2019.02.26-2019.03.07 前10天这些玩家的排位赛数据,选手需要根据历史对局表现来预测2019.03.07当天测试集中的账号是否存在代练行为。
数据下载:https://gslab.qq.com/html/competition/20190311/index.htm
我本身就很喜欢玩LOL,所以做起来也感觉比较有意思,熬了两天夜给做完了,最后准确率86%,召回率73%,score是82
首先看到txt的数据文件,多达仅500W行,最大的数据文件大小约1G,每次load起来太慢了,于是我用pandas读取后转成了numpy的矩阵类型然后直接存成了npy文件,npy存取都是用二进制,之后load的速度会有大大提升。
行为流水和战绩流水数据文件中有着诸多玩家10天以来的所有对局,我先筛选出每一个玩家,再计算各个变量。这里变量是根据文件所提供的数据和我自己根据对英雄联盟的了解来选取的。
共提取了32个特征(变量)
1 |
单双排位占比 |
2 | 最常用英雄占比 |
3 | 平均游戏时长 |
4 | 秒均击杀 |
5 | 秒均死亡 |
6 | 秒均助攻 |
7 | 平均每局对局中最大连杀 |
8 | 平均对局平均分 |
9 | 胜率 |
10 | (不屈)败方评价分最高占败局比 |
11 | 对方投降在胜局中占比 |
12 | 游戏时长大于25分钟占比 |
13 | Carry局在胜局中占比 |
14 | 被虐局在败局中占比 |
15 | 尽力局在胜局中占比 |
16 | 碾压局在胜局中占比 |
17 | 躺赢局在胜局中占比 |
18 | 杀人最多占比 |
19 | 金钱最多占比 |
20 | 不可思议连杀占比(应该就是超神占比) |
21 | MVP占胜局比 |
22 | 补兵王占比 |
23 | 逃跑占比 |
24 | 对英雄伤害最高占比 |
25 | 秒均造成伤害 |
26 | 秒均收到伤害 |
27 | 秒均获得金币 |
28 | 场均最大连杀 |
29 | 场均最大多杀 |
30 | 场均补刀。如果是打野,计算秒均中立生物*1.4+小兵,如果不是打野,计算秒均小兵。通过是否携带惩戒在判断是不是打野 |
31 | KDA |
32 | 游戏局数 |
提取出这些特征后就变成了 17W行,也就是17W个玩家样本,32列,也就是32个特征变量的矩阵。并通过训练集和测试集的玩家目录把17W个玩家分开(一共有1W个测试样本)。
之后我是用的Sklearn提供的SVM直接进行模型建立,并把训练集按6:4分成了训练集和验证集。在未加任何处理的情况下准确率大约是90%,召回率0%-40%都出现过,非常不稳定。
我们排名的根据是,其中P是准确率,R是召回率。我的得分很不稳定而且很低。我在sklearn文档里面找到了一段说,训练的时候尽量进行归一化。我尝试了这种方法,果真有奇效。
scaler = StandardScaler()
scaler.fit(training_x)
trans_training_x = scaler.transform(training_x)
scaler.fit(test_x)
trans_test_x=scaler.transform(test_x)
上述就是归一化的代码,一定要注意不仅要对training set进行归一,还要对test set进行归一。否则整个结果就毫无意义。
在归一化后我的召回率稳定在了40%,准确率90%。准确率和召回率的差距太大,这样子最后的得分也非常的低。我想到了这是一个样本类别非常不均衡的训练。因为代练玩家本身只占少数,所以在最后要把SVM中把玩家本是代练,却判错为正常玩家的惩罚提高。
最后我选择了如下的参数(1代表代练玩家,0代表正常玩家):
weight_dict=dict()
weight_dict[1]=4
weight_dict[0]=float(4)/7
clf=SVC(class_weight=weight_dict,
C=1.0,
kernel='rbf',
gamma='scale'
)
其实class_weight参数中有一个很现成的选项是"balanced",在这种情况下C[i]=n_samples / (n_classes * np.bincount(y))。具体请见sklearn关于svm的文档:https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
其实在大多数非平衡情况下class_weight=”balanced“就可以解决问题。但在本题score的定义下,我自己尝试了多种weight_dict,最后还是4和4/7得到的score是最高的。最后得到了准确率86%,召回率73%,分数有82,进入了决赛。问到一个人说他的分数有87,不知道怎么办到的。
进决赛了很开心,就当是免费去深圳旅游了。这次初赛这个项目我本身是非常喜欢的,说到遗憾就是没有加让玩家rank分数这个特征,还有数据预处理阶段写了太多不必要的操作,导致在特征提取过程中程序运行了14个小时。我想优点就是能够有诸如KDA、打野和线上补兵调整这些不玩LOL的人不会有的数据处理操作,当然也使得最终结果有一定提升。
今天腾讯HR打电话来说因为我之前参加了腾讯面试,所以这次所谓的面试绿色通道对我没有用……就相当于这个面试通道只是可以提供一个立即初试的机会,然而我之前已经面过初试。 ORZ 突然就不知道到底我是为了什么要参赛了,有点沮丧。
我真的没有想到过要去一个实习会有这么难。什么时候才能到各家公司直接来找我呢?