欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!
对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。
作者:海笛heidi
个人公众号: 废才数据挖掘
绝地求生相信大家都比较熟悉,本次推文就是利用kaggle数据预测玩家排名情况,有兴趣的小伙伴可在kaggle下载数据,数据链接
:https://www.kaggle.com/c/pubg-finish-placement-prediction
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
from sklearn.model_selection import GridSearchCV
import lightgbm as lgb
from sklearn.cross_validation import train_test_split,cross_val_score
from sklearn.model_selection import StratifiedKFold,KFold,StratifiedShuffleSplit
import lightgbm as lgb
import seaborn as sns
import warnings
import card
import time
import gc, sys
matplotlib.use('qt4agg')#指定默认字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family']='sans-serif'#解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
pd.set_option('display.max_rows', 100)
pd.set_option('display.max_columns', 10000)
%matplotlib inline
warnings.filterwarnings("ignore")
plt.style.use('ggplot')
导入数据
def file():
train=pd.read_csv("d:/data/PUBG/train_V2.csv")
test=pd.read_csv("d:/data/PUBG/test_V2.csv")
sub=pd.read_csv("d:/data/PUBG/sample_submission_V2.csv")
return train ,test ,sub
a=time.time()
train ,test ,sub=file()
b=time.time()
costime=b-a
print(costime)
我们先看下原始特征名称
oldname=['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']
为了方便,小编在这里把变量改为中文名,部分翻译不太准确,敬请谅解。
train.columns=['Id', 'groupId', 'matchId', '助攻数', '使用药品', '总伤害','击倒数',
'爆头杀敌', '治疗', '杀敌数排名', '杀敌数外部排名', '杀敌数',
'短时间最大杀敌', '死亡前最大时间', '比赛时间', '比赛类型', 'maxPlace',
'有数据的组数', 'Elo玩家排名', 'revives', '车辆行驶距离', '路上杀敌数'
, '游泳距离', '杀队友次数', '摧毁车辆数', '步行距离',
'捡拾武器数', '积分', 'target']
现在我们来做一下简单的EDA
PUBG=train.copy()
PUBG.head()
比赛时间为千位数,为了方便大家认知,把时间除以100得到场均存活分钟数
PUBG["比赛时间"]=PUBG["比赛时间"]//100
我们先来看看特征与target的相关性
corr_target=PUBG.corr()["target"]
corr_target=corr_target.reset_index()
corr_target.columns=["features","target"]
corr_target=corr_target.sort_values(by="target",ascending=False)
可以看见步行距离与target有这很高相关性,其次为嗑药数。
可视化相关系数:
def bar(x,y):
plt.figure(figsize=(8,11))
plt.yticks(fontsize=20)
sns.barplot(x,y)
bar(corr_target["target"],corr_target["features"])
为了方便我们统计分析,小编把target==1,定义为“吃鸡”。
PUBG["target"]=PUBG["target"].apply(lambda x : 0 if x<1 else 1)
PUBG["target"].value_counts()
def findnumric(df):
types=pd.DataFrame(df.dtypes)
numric=types[types[0]!="object"].index.tolist()
return numric
name=findnumric(PUBG)
name
我们来看一下有哪些特征数属于数值型
对部分特征简单可视化。
def echarts_barplot(df,var,target):
from pyecharts import Bar
a=df.groupby([var])[target].mean().reset_index()
b=df.groupby([var])[target].count().reset_index()
b=b.merge(a,on=var,how="left").rename(columns={target+"_x":"counts",target+"_y":"rate"})
group=b
group=group.sort_index(by="counts",ascending=False)
group["占比"]=group["counts"]/group["counts"].sum()
group["累计"]=group["占比"].cumsum()
bar = Bar("{}__吃鸡概率柱状图".format(var))
bar.add("{}".format(var), group[var],group["rate"])
#bar.render()
return bar
可以看见大部分特征均是随着数值升高,吃鸡概率也相应增加,跟相关性关系也比较吻合
比较有趣的事情是,有部分选手比较时间小于1分钟,落地成盒党最后的吃鸡概率竟然为100%。这个也说明有部分人是属于躺鸡状态,所以我们后期做特征工程的时候需要考虑其队友的数据。
趣味分析:
比如爆头率,按照常理来说,爆头率越高,代表枪法越准,吃鸡可能性可能会更大一下,但是事实上真的是这样吗?
如上图,我们发现爆头率达到0.9以上的选手,最后吃鸡的概率大概在0.5,而爆头率只有0.07的选手吃鸡概率达到100%,或许数据未处理的图表看着不太准确,下面小编则用数据离散后的图表做分析
由上图得知,分组为2的吃鸡概率最大,平均达到0.21,爆头率大于0.5的分组,最后的吃鸡概率仅为0.05。结论,过于追求完美的选手,用一句俗话,装逼被雷劈,把敌人杀死才最重要。小伙伴们,想吃鸡,就不要刻意追求爆头
有些选手在玩吃鸡的时候,比较喜欢在路途中杀敌,抢“快递员”物质,抢得越多,物质越多,对最终的决赛越有利??这是真的吗??
上图可以看出路杀率在[0.1,0.3)之间的小伙伴最终吃鸡概率最高,反而是那些喜欢堵桥啊,守点的选手吃鸡概率仅为0.025。这种情况很明显是吃鸡不成折把米,以为是别人给他送“快递”呢,真正的高手,都会选择尽快占领制高点,最终吃鸡也是顺理成章的事情。
maping={"squad-fpp":"squad",
"duo-fpp":"duo",
"solo-fpp":"solo",
"duo":"duo",
"solo":"solo",
"normal-squad-fpp":"squad",
"crashfpp":"other",
"normal-duo-fpp":"duo",
"flaretpp":"other",
"normal-solo-fpp":"solo",
"flarefpp":"other",
"normal-duo-fpp":"duo",
"normal-duo":"duo",
"normal-squad":"squad",
"crashtpp":"other",
"normal-solo":"solo"}
PUBG["比赛类型"]=PUBG["比赛类型"].map(maping)
小编把比赛类型进行重新分组
不出意料,妥妥四排吃鸡概率最高。
其余的数据,小编就不在这里详细分析了,有兴趣的小伙伴,做一个比较详细的EDA。言归正传,我们现在开始正式的特征工程。
def addfeature(train):
train["爆头率"]=train["爆头杀敌"]/train["杀敌数"]
train["短时间最大杀敌率"]=train["短时间最大杀敌"]/train["杀敌数"]
train["路上杀敌数率"]=train["路上杀敌数"]/train["杀敌数"]
train["误杀率"]=train["杀队友次数"]/train["杀敌数"]
train["治疗+使用药品"]=train["治疗"]+train["使用药品"]
train["总行动距离"]=train["车辆行驶距离"]+train["游泳距离"]+train["步行距离"]
train["杀敌数排名/maxPlace"]=train["杀敌数排名"]/train["maxPlace"]
train["爆头/杀敌数"]=train["杀敌数"]/train["爆头杀敌"]
train["总行动距离/拾取武器"]=train["总行动距离"]/train["捡拾武器数"]
train["步行距离/治疗"]=train["步行距离"]/train["治疗"]
train["步行距离/杀敌数"]=train["步行距离"]/train["杀敌数"]
train["步行距离/击倒数"]=train["步行距离"]/train["击倒数"]
train["步行距离/使用药品"]=train["步行距离"]/train["使用药品"]
train["步行距离/摧毁车辆数"]=train["步行距离"]/train["摧毁车辆数"]
train["步行距离/车辆行驶距离"]=train["步行距离"]/train["车辆行驶距离"]
train["步行距离/游泳距离"]=train["步行距离"]/train["游泳距离"]
train["步行距离/使用药品"]=train["步行距离"]/train["使用药品"]
train['杀敌数/步行距离'] = train['杀敌数'] / train['步行距离']
train["车辆行驶距离/治疗"]=train["车辆行驶距离"]/train["治疗"]
train["车辆行驶距离/杀敌数"]=train["车辆行驶距离"]/train["杀敌数"]
train["车辆行驶距离/击倒数"]=train["车辆行驶距离"]/train["击倒数"]
train["车辆行驶距离/使用药品"]=train["车辆行驶距离"]/train["使用药品"]
train["车辆行驶距离/摧毁车辆数"]=train["车辆行驶距离"]/train["摧毁车辆数"]
train["车辆行驶距离/车辆行驶距离"]=train["车辆行驶距离"]/train["车辆行驶距离"]
train["车辆行驶距离/游泳距离"]=train["车辆行驶距离"]/train["游泳距离"]
train["车辆行驶距离/使用药品"]=train["车辆行驶距离"]/train["使用药品"]
train['杀敌数/车辆行驶距离'] = train['杀敌数'] / train['车辆行驶距离']
train["击倒数/杀敌数"]=train["击倒数"]/train["杀敌数"]
train["击倒数/助攻数"]=train["击倒数"]/train["助攻数"]
train["击倒数/爆头杀敌"]=train["击倒数"]/train["爆头杀敌"]
train["击倒数-杀敌数"]=np.abs(train["击倒数"]-train["杀敌数"])
train["杀敌数-短时间最大杀敌"]=np.abs(train["杀敌数"]-train["短时间最大杀敌"])
train["助攻数/击倒数"]=train["助攻数"]/train["击倒数"]
train["助攻数-杀敌数"]=np.abs(train["助攻数"]-train["杀敌数"])
train["爆头+路杀"] = train["爆头杀敌"] + train["路上杀敌数"]
train["总伤害/杀敌数"]=train["总伤害"]/train["杀敌数"]
train["总伤害/助攻数"]=train["总伤害"]/train["助攻数"]
train["总伤害/短时间最大杀敌"]=train["总伤害"]/train["短时间最大杀敌"]
train["总伤害/路上杀敌数"]=train["总伤害"]/train["路上杀敌数"]
train["总伤害/爆头杀敌"]=train["总伤害"]/train["爆头杀敌"]
train["总伤害/击倒数"]=train["总伤害"]/train["击倒数"]
train["总伤害/治疗"]=train["总伤害"]/train["治疗"]
train["使用药品-杀敌数"]=np.abs(train["使用药品"]-train["杀敌数"])
train["使用药品/杀敌数"]=train["使用药品"]/train["杀敌数"]
train["使用药品/治疗"]=train["使用药品"]/train["治疗"]
train["使用药品-治疗"]=np.abs(train["使用药品"]-train["治疗"])
train["车辆行驶距离/路上杀敌数"]=train["车辆行驶距离"]/train["路上杀敌数"]
train["助攻数/杀敌数"]=train["助攻数"]/train["杀敌数"]
train["杀敌数/助攻数"]=train["杀敌数"]/train["助攻数"]
train["杀敌数/捡拾武器数"]=train["杀敌数"]/train["捡拾武器数"]
train["捡拾武器数/杀敌数"]=train["捡拾武器数"]/train["杀敌数"]
train["比赛时间1"]=train["比赛时间"]//100
train["死亡前最大时间"]=train["死亡前最大时间"]/100
train["比赛时间/杀敌数"]=train["比赛时间1"]/train["杀敌数"]
train["比赛时间/击倒数"]=train["比赛时间1"]/train["击倒数"]
train["比赛时间/爆头杀敌"]=train["比赛时间1"]/train["爆头杀敌"]
train["比赛时间/路上杀敌数"]=train["比赛时间1"]/train["路上杀敌数"]
train["死亡前最大时间/比赛时间"]=train["死亡前最大时间"]/train["比赛时间1"]
print("Removing Na's From DF")
train[train == np.inf] = np.NaN
train[train == np.NINF] = np.NaN
train.fillna(0, inplace=True)
features = list(train.columns)
target = "target"
if target in features:
y=train[target]
features.remove(target)
train=train[features]
else:
y=None
train=train[features]
#自己流弊不流弊不重要,重要的是跟对队友才重要,现在计算组队情况
feature=['助攻数', '使用药品', '总伤害', '击倒数', '爆头杀敌', '治疗',
'杀敌数排名', '杀敌数外部排名', '杀敌数', '短时间最大杀敌', '比赛时间',
'Elo玩家排名', '路上杀敌数', '积分','总行动距离','捡拾武器数',"死亡前最大时间"]
print("group mean")
start=time.time()
agg = train.groupby(['matchId','groupId'])[feature].agg('mean').reset_index()
train=train.merge(agg, suffixes=["", "_mean"], how='left', on=['matchId','groupId'])
print("preparing rank ...")
agg_rank = train.groupby(['matchId','groupId'])[feature].agg('min').rank(pct=True).reset_index()
print("rank complete")
train = train.merge(agg_rank, suffixes=["", "_mean_rank"], how='left', on=['matchId', 'groupId'])
end=time.time()
print("cost time {:.2f}mins".format((end-start)/60))
del agg ,agg_rank
gc.collect()
print("group min")
start=time.time()
agg = train.groupby(['matchId','groupId'])[feature].agg('min').reset_index()
train=train.merge(agg, suffixes=["", "_min"], how='left', on=['matchId','groupId'])
print("preparing rank ...")
agg_rank = train.groupby(['matchId','groupId'])[feature].agg('min').rank(pct=True).reset_index()
print("rank complete")
train = train.merge(agg_rank, suffixes=["", "_min_rank"], how='left', on=['matchId', 'groupId'])
end=time.time()
print("cost time {:.2f}mins".format((end-start)/60))
del agg ,agg_rank
gc.collect()
print("group max")
start=time.time()
agg = train.groupby(['matchId','groupId'])[feature].agg('max').reset_index()
train=train.merge(agg, suffixes=["", "_max"], how='left', on=['matchId','groupId'])
print("preparing rank ...")
agg_rank = train.groupby(['matchId','groupId'])[feature].agg('max').rank(pct=True).reset_index()
print("rank complete")
train = train.merge(agg_rank, suffixes=["", "_max_rank"], how='left', on=['matchId', 'groupId'])
end=time.time()
print("cost time {:.2f}mins".format((end-start)/60))
del agg ,agg_rank
gc.collect()
print("group size")
start=time.time()
agg = train.groupby(['matchId','groupId'])[feature].size().reset_index()
train=train.merge(agg, suffixes=["", "_size"], how='left', on=['matchId','groupId'])
print("preparing rank ...")
agg_rank = train.groupby(['matchId','groupId'])[feature].agg('size').rank(pct=True).reset_index()
print("rank complete")
train = train.merge(agg_rank, suffixes=["", "_size_rank"], how='left', on=['matchId', 'groupId'])
end=time.time()
print("cost time {:.2f}mins".format((end-start)/60))
del agg ,agg_rank
gc.collect()
print("group sum")
start=time.time()
agg = train.groupby(['matchId','groupId'])[feature].agg('sum').reset_index()
train=train.merge(agg, suffixes=["", "_sum"], how='left', on=['matchId','groupId'])
print("preparing rank ...")
agg_rank = train.groupby(['matchId','groupId'])[feature].agg('sum').rank(pct=True).reset_index()
print("rank complete")
train = train.merge(agg_rank, suffixes=["", "_sum_rank"], how='left', on=['matchId', 'groupId'])
end=time.time()
print("cost time {:.2f}mins".format((end-start)/60))
del agg ,agg_rank
gc.collect()
variable=list(train.columns)
variable.remove("Id")
variable.remove("matchId")
variable.remove("groupId")
variable.remove("比赛类型")
train=train[variable]
return train, y
def reduce_mem_usage(df):
""" iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum()
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)
else:
df[col] = df[col].astype('category')
end_mem = df.memory_usage().sum()
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
一般数据需要分为训练集跟测试集,有时候数据划分的好坏,直接决定模型的结果。我们先来看一下不交叉验证的模型算法结果。
train_X,val_X,train_y,val_y=train_test_split(train,y,test_size=0.3)
def run_lgb(train_X, train_y, val_X, val_y, x_test):
params = {"objective" : "regression", "metric" : "mae", 'n_estimators':20000, 'early_stopping_rounds':200,
"num_leaves" : 50, "learning_rate" : 0.05, "bagging_fraction" : 0.7,"max_depth":-1,
"bagging_seed" : 0, "num_threads" : 4,"colsample_bytree" : 0.7
}
lgtrain = lgb.Dataset(train_X, label=train_y)
lgval = lgb.Dataset(val_X, label=val_y)
model = lgb.train(params, lgtrain, valid_sets=[lgtrain, lgval], early_stopping_rounds=200, verbose_eval=100)
pred_test_y = model.predict(x_test, num_iteration=model.best_iteration)
return pred_test_y, model
小编在这里迭代两万步,最后mase得分在0.0378831
lgb_model = lgb.LGBMClassifier(boosting_type='gbdt', num_leaves=100, reg_alpha=3, reg_lambda=5, max_depth=-1,
n_estimators=8000, objective='binary', subsample=0.9, colsample_bytree=0.77, subsample_freq=1, learning_rate=0.02,
random_state=1000, n_jobs=16, min_child_weight=4, min_child_samples=5, min_split_gain=0)
skf = StratifiedKFold(n_splits=5, random_state=2018, shuffle=True)
best_score = []
oof_preds = np.zeros(train.shape[0])
for index, (train_index, test_index) in enumerate(skf.split(train, y)):
lgb_model.fit(train.iloc[train_index], y.iloc[train_index], verbose=50,
eval_set=[(train.iloc[train_index], y.iloc[train_index]),
(train.iloc[test_index], y.iloc[test_index])], early_stopping_rounds=30)
best_score.append(lgb_model.best_score_['valid_1']['binary_logloss'])
print(best_score)
oof_preds[test_index] = lgb_model.predict_proba(train.iloc[test_index], num_iteration=lgb_model.best_iteration_)[:,1]
利用交叉验证,对结果取平均,迭代8000次的时候,loss已经达到0.028289,效果比之前明显好很多,而且在8000步的时候并没有early_stopping,其实还有下降空间。小编并没有对数据做特征筛选,特征工程也只是各种无脑加,做特征筛选后,效果可能会更好一点,这里就不做了。
吃鸡结论:不要爆头,不要当拦路虎,多四排,大吉大利,今晚吃鸡!!!

Python的爱好者社区历史文章大合集:
2018年Python爱好者社区历史文章合集(作者篇)
2018年Python爱好者社区历史文章合集(类型篇)
关注后在公众号内回复“ 课程 ”即可获取:
小编的转行入职数据科学(数据分析挖掘/机器学习方向)【最新免费】
小编的Python的入门免费视频课程!
小编的Python的快速上手matplotlib可视化库!
崔老师爬虫实战案例免费学习视频。
陈老师数据分析报告扩展制作免费学习视频。
玩转大数据分析!Spark2.X + Python精华实战课程免费学习视频。
网友评论