PUBG Finish Placement Prediction (Kernels Only)
比赛网址:https://www.kaggle.com/c/pubg-finish-placement-prediction/data
问题背景:
在PUBG游戏中,每场比赛最多有100名玩家,玩家可以根据在自己被淘汰时还有多少玩家活着从而获得比赛排名。 在游戏中,玩家可以拿起不同的武器攻击敌人,也可以恢复被击倒但未被杀死的队友,驾驶车辆,游泳,跑步,射击,并承担相应的结果-例如跑太远或被敌人杀死。为了赢得比赛,你需要获取武器和可用设备以消灭其他人并生存到最后。因此,如果你想看到’大吉大利,今晚吃鸡!’ ,根据实际情况制定一些合理的策略是非常有益的。例如,一个合适的跳伞位置可以帮助你更快地收集装备,你从不断缩小的蓝色圆圈区域中逃脱的路径(蓝色区域外玩家将不断受到伤害直到死亡)可以帮助你避免一些危险的敌人并找到一个合适的位置隐藏在最后一个圈子有助于获得’大吉大利,今晚吃鸡’。
你将获得大量匿名的PUBG游戏统计数据,其格式设置为每行包含一个玩家的游戏后统计数据。你将创建一个模型,根据他们的最终统计数据预测他们的相应排名。
3.目的:
鉴于先前玩家在每场比赛期间的统计数据和训练数据中的排名信息,我们需要训练模型根据每场比赛期间的统计数据预测测试组中球员的排名。目标标签排名将是0到1之间的百分比值,更高的百分比表示该匹配中的更高排名。在这个过程中,我们将分析诸多因素对获胜的影响。
4.数据字段(变量含义):
DBNOs : 玩家击倒的敌人数量
assists : 玩家造成伤害且被队友所杀死的敌人数量
boosts : 玩家使用的增益性物品数量
damageDealt : 玩家造成的总伤害-玩家所受的伤害
headshotKills : 玩家通过爆头杀死的敌人数量
heals : 玩家使用的救援类物品数量
Id : 玩家的ID
killPlace : 玩家杀死敌人数量的排名
killPoints : 基于杀戮的玩家外部排名。
killStreaks : 玩家在短时间内杀死敌人的最大数量
kills : 玩家杀死的敌人的数量
longestKill : 玩家和玩家在死亡时被杀的最长距离。
matchDuration : 比赛时间
matchId : 比赛的ID
matchType : 单排/双排/四排;标准模式是“solo”,“duo”,“squad”,“solo-fpp”,“duo-fpp”和“squad-fpp”; 其他模式来自事件或自定义匹配。
rankPoints : 类似Elo的玩家排名。
revives : 玩家救援队友的次数
rideDistance : 玩家使用交通工具行驶了多少米
roadKills : 玩家在交通工具上杀死敌人的数目
swimDistance : 玩家游泳的距离
teamKills : 该玩家杀死队友的次数
vehicleDestroys : 玩家毁坏的交通工具数目
walkDistance : 玩家步行距离
weaponsAcquired : 玩家捡枪数量
winPoints : 基于赢的玩家外部排名。
groupId : 队伍的ID
numGroups : 在该局比赛中有玩家数据的队伍数量
maxPlace : 在该局中已有数据的最差的队伍名次
winPlacePerc : 预测目标,是以百分数计算的,介于0-1之间,1对应第一名,0对应最后一名。 它是根据maxPlace计算的,而不是numGroups,因此匹配中可能缺少某些队伍。
实现思路
我们主要采用线性回归的方式进行数据分析与探索,并取得了较好的效果。我们将在线性回归基础上,采用神经网络、GBR、Light GBM的方式提升性能,最终取得了较好的效果。
我们采用单独分析与综合分析相结合的方式,对诸多因素进行筛选,选出最重要的影响因素,并分析其对最终排名的影响,当然我们首先进行了单变量、双变量的数据探索性分析,得到诸多结论,并结合这些结论进行多变量数据探索分析,得到了我们最终的模型。
我们调用了常用的python数据处理相关的库进行使用
1.基础工作
import:调用加载相关的库
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
读取数据集:(将数据保存在train变量中)
train = pd.read_csv('train_V2.csv')
查看数据中包含的变量以及相应的变量类型(用以方便之后的操作)
train.info()
运行结果如下:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4446966 entries, 0 to 4446965
Data columns (total 29 columns):
Id object
groupId object
matchId object
assists int64
boosts int64
damageDealt float64
DBNOs int64
headshotKills int64
heals int64
killPlace int64
killPoints int64
kills int64
killStreaks int64
longestKill float64
matchDuration int64
matchType object
maxPlace int64
numGroups int64
rankPoints int64
revives int64
rideDistance float64
roadKills int64
swimDistance float64
teamKills int64
vehicleDestroys int64
walkDistance float64
weaponsAcquired int64
winPoints int64
winPlacePerc float64
dtypes: float64(6), int64(19), object(4)
memory usage: 983.9+ MB
我们可以得到数据中的变量以及相关的变量内容,便于之后的分析与操作。值得一提的是,这里的数据集980+MB,是一个非常大量的数据集。
我们查看前15组数据:
train.head(15)
结果如下:
Id | groupId | matchId | assists | boosts | damageDealt | DBNOs | headshotKills | heals | killPlace | killPoints | kills | killStreaks | longestKill | matchDuration | matchType | maxPlace | numGroups | rankPoints | revives | rideDistance | roadKills | swimDistance | teamKills | vehicleDestroys | walkDistance | weaponsAcquired | winPoints | winPlacePerc | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7f96b2f878858a | 4d4b580de459be | a10357fd1a4a91 | 0 | 0 | 0.000000 | 0 | 0 | 0 | 60 | 1241 | 0 | 0 | 0.00000 | 1306 | squad-fpp | 28 | 26 | -1 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 244.7500 | 1 | 1466 | 0.444336 |
1 | eef90569b9d03c | 684d5656442f9e | aeb375fc57110c | 0 | 0 | 91.500000 | 0 | 0 | 0 | 57 | 0 | 0 | 0 | 0.00000 | 1777 | squad-fpp | 26 | 25 | 1484 | 0 | 0.004501 | 0 | 11.039062 | 0 | 0 | 1434.0000 | 5 | 0 | 0.640137 |
2 | 1eaf90ac73de72 | 6a4a42c3245a74 | 110163d8bb94ae | 1 | 0 | 68.000000 | 0 | 0 | 0 | 47 | 0 | 0 | 0 | 0.00000 | 1318 | duo | 50 | 47 | 1491 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 161.7500 | 2 | 0 | 0.775391 |
3 | 4616d365dd2853 | a930a9c79cd721 | f1f1f4ef412d7e | 0 | 0 | 32.906250 | 0 | 0 | 0 | 75 | 0 | 0 | 0 | 0.00000 | 1436 | squad-fpp | 31 | 30 | 1408 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 202.7500 | 3 | 0 | 0.166748 |
4 | 315c96c26c9aac | de04010b3458dd | 6dc8ff871e21e6 | 0 | 0 | 100.000000 | 0 | 0 | 0 | 45 | 0 | 1 | 1 | 58.53125 | 1424 | solo-fpp | 97 | 95 | 1560 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 49.7500 | 2 | 0 | 0.187500 |
5 | ff79c12f326506 | 289a6836a88d27 | bac52627a12114 | 0 | 0 | 100.000000 | 1 | 1 | 0 | 44 | 0 | 1 | 1 | 18.43750 | 1395 | squad-fpp | 28 | 28 | 1418 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 34.6875 | 1 | 0 | 0.036987 |
6 | 95959be0e21ca3 | 2c485a1ad3d0f1 | a8274e903927a2 | 0 | 0 | 0.000000 | 0 | 0 | 0 | 96 | 1262 | 0 | 0 | 0.00000 | 1316 | squad-fpp | 28 | 28 | -1 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 13.5000 | 1 | 1497 | 0.000000 |
7 | 311b84c6ff4390 | eaba5fcb7fc1ae | 292611730ca862 | 0 | 0 | 8.539062 | 0 | 0 | 0 | 48 | 1000 | 0 | 0 | 0.00000 | 1967 | solo-fpp | 96 | 92 | -1 | 0 | 2004.000000 | 0 | 0.000000 | 0 | 0 | 1089.0000 | 6 | 1500 | 0.736816 |
8 | 1a68204ccf9891 | 47cfbb04e1b1a2 | df014fbee741c6 | 0 | 0 | 51.593750 | 0 | 0 | 0 | 64 | 0 | 0 | 0 | 0.00000 | 1375 | squad | 28 | 27 | 1493 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 800.0000 | 4 | 0 | 0.370361 |
9 | e5bb5a43587253 | 759bb6f7514fd2 | 3d3031c795305b | 0 | 0 | 37.281250 | 0 | 0 | 0 | 74 | 0 | 0 | 0 | 0.00000 | 1930 | squad | 29 | 27 | 1349 | 0 | 0.000000 | 0 | 0.000000 | 0 | 0 | 65.6875 | 1 | 0 | 0.214355 |
10 | 2b574d43972813 | c549efede67ad3 | 2dd6ddb8320fc1 | 0 | 0 | 28.380 | 0 | 0 | 0 | 75 | 0 | 0 | 0 | 0.00 | 1811 | squad-fpp | 29 | 29 | 1475 | 0 | 0.0000 | 0 | 0.00 | 0 | 0 | 868.30 | 9 | 0 | 0.3929 |
11 | 8de328a74658a9 | f643df9df3877c | 80170383d90003 | 0 | 0 | 137.900 | 1 | 0 | 0 | 64 | 0 | 0 | 0 | 0.00 | 1384 | duo-fpp | 48 | 46 | 1488 | 0 | 0.0000 | 0 | 0.00 | 0 | 0 | 451.70 | 1 | 0 | 0.4043 |
12 | ce4f6ac165705e | da24cdb91969cc | 535b5dbd965a94 | 0 | 0 | 0.000 | 0 | 0 | 0 | 37 | 0 | 0 | 0 | 0.00 | 1774 | squad-fpp | 29 | 28 | 1766 | 0 | 6639.0000 | 0 | 0.00 | 0 | 0 | 2784.00 | 6 | 0 | 0.9286 |
13 | b7807186e3f679 | 3c08e461874749 | 2c30ddf481c52d | 0 | 1 | 324.200 | 0 | 1 | 5 | 5 | 986 | 4 | 1 | 49.83 | 1886 | solo-fpp | 97 | 94 | -1 | 0 | 1228.0000 | 0 | 76.84 | 0 | 0 | 2050.00 | 6 | 1462 | 0.8750 |
14 | 8e244ac61b6aab | d40d0c7d3573a1 | 94e1c1cc443c65 | 0 | 1 | 122.800 | 1 | 0 | 2 | 25 | 1411 | 1 | 1 | 37.91 | 1458 | squad-fpp | 31 | 30 | -1 | 1 | 1237.0000 | 0 | 60.29 | 0 |
至此,我们完成了数据的读取,大致了解了数据集的内容以及相关的细节。基于此,我们将开始对数据进行处理与分析,并完成所求,我们将循序渐进地对数据进行探索。
我们在此处运用了CSDN上关于大数据处理的一些方法,有效的降低了数据所占的内存空间。主要思路为将部分所占空间大的数据类型在不失去数据的情况下将其改为所占空间较小的数据类型,我们将依次遍历,最终将内存降低了一半以上。例如: 对于kills,发现它的绝对值不超过50,所以可以将原本int64的数据类型转为int8,这样对于1MB的数据能压缩至0.125MB。基于该思路我们实现了数据占用空间的有效压缩。
def reduce_mem_usage(df):
start_mem = df.memory_usage().sum() / 1024**2
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
for col in df.columns:
col_type = df[col].dtype
if col_type != object:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
end_mem = df.memory_usage().sum() / 1024**2
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
return df
运行结果:
Memory usage of dataframe is 983.90 MB
Memory usage after optimization is: 288.39 MB
Decreased by 70.7%
2.基础数据探索
在单变量数据探索中,我们基于自己的游戏体验,较为感兴趣且认为较为重要的变量为玩家在每一局的杀敌数、造成的伤害值、步行距离、玩家捡枪数量、玩家使用的救援类物品数量。我们将对数据集中的这些变量进行探索式研究,了解变量的分布以及特点。我们认为这些因素对于一场比赛是否能够取得更高的名次有着较大影响,当然我们最终会通过相关性来验证我们的猜想。
杀敌数
我们将通过对数据集中杀敌数进行统计并以树状图形式形象地显示:
在这里由于杀敌数总体分布取值是分散的,但是我们通过经验可知杀敌数普遍是较少的,故我们采用分位数的数学办法对数据进行一次提取,我们选取的分位数为0.99,从而保证几乎所有的杀敌数都被包括在其中。
#average_killers表示平均杀敌数
average_killers=train['kills'].mean()
#most_killer_max表示杀敌数的0.99分位数,也就是意味着99%的数据小于该数字
most_killer_max=train['kills'].quantile(0.99)
#max_killers表示数据中最大的杀敌数 (该数据是由于我们的兴趣想得知的)
max_killers=train['kills'].max()
#将其输出
print("The average person kills {:.4f} players, 99% of people have {} kills or less, while the most kills ever recorded is {}.".format(average_killers,most_killer_max, max_killers))