Oh-Seung-Rok

안녕하세요. 정량적인 분석을 통해 제품-서비스를 개선하고 소비자들의 욕구를 먼저 파악하는 분석가가 되고 싶은 오승록입니다. 포트폴리오 [https://seungrok0317.com]

Project - PUBG - 승리에 미치는 요소 분석

05 Apr 2021 » Analyze_Project

PUBG - Finish Placement Prediction

  • 65,000 게임의 데이터 셋을 이용하여 플레이어들이 전장에서 벌이는 모든 행위를 분류하여 승리를 예측하는 데이터 셋이다.
  • 데이터 셋 : https://www.kaggle.com/c/pubg-finish-placement-prediction/data
  • 데이터 셋의 경우 PUBG의 개발자 API를 통해 수집한 데이터를 Kaggle에서 그대로 가져왔다고 한다.

라이브러리 및 데이터 불러오기

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

train_df = pd.read_csv('./pubg-finish-placement-prediction/train_V2.csv')
test_df = pd.read_csv('./pubg-finish-placement-prediction/test_V2.csv')

pd.set_option('display.max_columns', None)
train_df.tail(10)
IdgroupIdmatchIdassistsboostsdamageDealtDBNOsheadshotKillshealskillPlacekillPointskillskillStreakslongestKillmatchDurationmatchTypemaxPlacenumGroupsrankPointsrevivesrideDistanceroadKillsswimDistanceteamKillsvehicleDestroyswalkDistanceweaponsAcquiredwinPointswinPlacePerc
4446956dae05e0d7430593902915a7a194397b64a07c0576110151.90001770000.001693squad-fpp2928150010.000.00000828.30700.1071
44469572a4163ccbe0e3b2689c981578849eebc058a45ff1301100.000003201112.021396duo-fpp4949154610.000.00000363.70200.4583
4446958837349af7e8a3558bc41049356232001300d4f5787000.00000920000.001414duo-fpp4844154600.000.000000.00000.0000
4446959d29bfa313ad766ac3f1b4a56e5ad2f3b1af94739b30022.68000890000.001456solo-fpp9695178700.000.0000040.25100.0842
444696069fa4c2d5431b12a3ad0e37fb6ce818ccf2160343f00327.70320404390.251936squad-fpp302814770180.400.00000845.60300.2414
4446961afff7f652dbc10d238e426f50de718492834ce5635000.00000741029000.001873squad-fpp2928-101292.000.000001019.00315070.1786
4446962f4197cf374e6c0408cdb5c46b2acee854b837376d90144.15000690000.001435solo9393150100.000.0000081.70600.2935
4446963e1948b1295c88ae26ac84bdf7cef6d0cd12784f1ab0059.06000660000.001321squad-fpp2828150000.002.18400788.70400.4815
4446964cc032cdd73b7acc2223f35411394c9c701d0ad758a04180.401121102198.501373squad-fpp2625141820.000.000002748.00800.8000
44469650d8e7ed728b6fd8c74f72fedf5ff62a16aabcc095c02268.000011802178.251766solo-fpp9894159001369.000.000001244.00500.5464
train_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4446966 entries, 0 to 4446965
Data columns (total 29 columns):
 #   Column           Dtype  
---  ------           -----  
 0   Id               object 
 1   groupId          object 
 2   matchId          object 
 3   assists          int64  
 4   boosts           int64  
 5   damageDealt      float64
 6   DBNOs            int64  
 7   headshotKills    int64  
 8   heals            int64  
 9   killPlace        int64  
 10  killPoints       int64  
 11  kills            int64  
 12  killStreaks      int64  
 13  longestKill      float64
 14  matchDuration    int64  
 15  matchType        object 
 16  maxPlace         int64  
 17  numGroups        int64  
 18  rankPoints       int64  
 19  revives          int64  
 20  rideDistance     float64
 21  roadKills        int64  
 22  swimDistance     float64
 23  teamKills        int64  
 24  vehicleDestroys  int64  
 25  walkDistance     float64
 26  weaponsAcquired  int64  
 27  winPoints        int64  
 28  winPlacePerc     float64
dtypes: float64(6), int64(19), object(4)
memory usage: 983.9+ MB
  • Id
  • groupId : 그룹 ID, 매치안에서 같은 그룹일 경우 같은 ID를 부여받는다.
  • matchId : 매치 ID, train, test에 중복된 match는 없다.
  • assists : 어시스트, 사살에 도움을 준 횟수
  • boosts : 사용된 부스트 아이템 개수
  • damageDealt : 가한 데미지 총합
  • DBNOs : 기절 시킨 적의 수
  • headshotKills : 헤드샷으로 사살한 적의 수
  • heals : 사용된 치유 아이템 개수
  • killPlace : 한 매치에서 킬 기준으로 집계된 등수
  • killPoints : 킬 기준 포인트
  • kills : 사살한 적의 수
  • killStreaks : 단 시간내 연속적으로 사살한 적의 수
  • longestKill : 최장으로 사살한 거리. (다소 오류가 있다고 한다.)
  • matchDuration : 매치 총 시간
  • matchType : 사용자가 지정한 매치 타입의 수 ex) solo, duo, squad, solo-fpp, 기타는 이벤트 또는 사용자 지정
  • maxPlace : 매치내 가장 낮은 등수. (다소 오류가 있음)
  • numGroups : 매치 내 총 팀의 수
  • rankPoints : 플레이어 순위. (일관성이 없고 오류가 많다.)
  • revives : 팀원을 살린 횟수
  • rideDistance : 탈것을 통해 이동한 총 거리
  • roadKills : 탈것으로 적을 죽인 횟수
  • swimDistance : 수영하여 이동한 총 거리
  • teamKills : 팀킬한 횟수
  • vehicleDestroys : 탈것을 파괴한 횟수
  • walkDistance : 걸어서 총 이동한 거리
  • weaponsAcquired : 총 획득 무기 수
  • winPoints : 승리 기준 포인트
  • winPlacePerc : 타겟데이터, 1은 1등, 0은 꼴등. 누락이 있다고 함.
train_df.isna().sum()
Id                 0
groupId            0
matchId            0
assists            0
boosts             0
damageDealt        0
DBNOs              0
headshotKills      0
heals              0
killPlace          0
killPoints         0
kills              0
killStreaks        0
longestKill        0
matchDuration      0
matchType          0
maxPlace           0
numGroups          0
rankPoints         0
revives            0
rideDistance       0
roadKills          0
swimDistance       0
teamKills          0
vehicleDestroys    0
walkDistance       0
weaponsAcquired    0
winPoints          0
winPlacePerc       1
dtype: int64
  • 비교적 잘 정돈된 데이터, 다만 오류가 있다는 longstkilll, maxplace, rankpoints 는 drop하는게 좋을 듯 하다.

EDA 및 기초 통계 분석

train_df.columns
Index(['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'],
      dtype='object')
  • Id, groupId, matchId 드랍, 승리한 group id만을 모아 특성을 분석할수도 있겠으나 다른 접근방식이므로 여기선 제거.
  • longestKill, maxPlace, rankPoints 역시 오류가 많은 데이터로 드랍

  • 딜량, 기절 시킨 적의 수, 사살한 적의 수, 킬 포인트는 직관적으로 ‘좋은 실력’ 과 큰 연관이 있어보인다.
  • 좋은 실력이 곧바로 우승으로 이어지는것인지는 더 분석해볼 여지가 있다.
  • 헤드샷이나 연속적으로 죽인 적의 수 역시 ‘좋은 실력’과 연관있어 보인다. (일반적으로 단순사살보다 난이도가 있기때문)
  • 어시스트, 부스트, 힐, 소생, 무기 취득, 탈것 파괴는 직관적으로 연관이 있어보이진 않는다.
  • 걷기, 수영, 탈것 역시 위와 마찬가지.
train_df.describe()
assistsboostsdamageDealtDBNOsheadshotKillshealskillPlacekillPointskillskillStreakslongestKillmatchDurationmaxPlacenumGroupsrankPointsrevivesrideDistanceroadKillsswimDistanceteamKillsvehicleDestroyswalkDistanceweaponsAcquiredwinPointswinPlacePerc
count4.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446966e+064.446965e+06
mean2.338149e-011.106908e+001.307171e+026.578755e-012.268196e-011.370147e+004.759935e+015.050060e+029.247833e-015.439551e-012.299759e+011.579506e+034.450467e+014.300759e+018.920105e+021.646590e-016.061157e+023.496091e-034.509322e+002.386841e-027.918208e-031.154218e+033.660488e+006.064601e+024.728216e-01
std5.885731e-011.715794e+001.707806e+021.145743e+006.021553e-012.679982e+002.746294e+016.275049e+021.558445e+007.109721e-015.097262e+012.587399e+022.382811e+012.328949e+017.366478e+024.721671e-011.498344e+037.337297e-023.050220e+011.673935e-019.261157e-021.183497e+032.456544e+007.397004e+023.074050e-01
min0.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+001.000000e+000.000000e+000.000000e+000.000000e+000.000000e+009.000000e+001.000000e+001.000000e+00-1.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+00
25%0.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+002.400000e+010.000000e+000.000000e+000.000000e+000.000000e+001.367000e+032.800000e+012.700000e+01-1.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+001.551000e+022.000000e+000.000000e+002.000000e-01
50%0.000000e+000.000000e+008.424000e+010.000000e+000.000000e+000.000000e+004.700000e+010.000000e+000.000000e+000.000000e+000.000000e+001.438000e+033.000000e+013.000000e+011.443000e+030.000000e+000.000000e+000.000000e+000.000000e+000.000000e+000.000000e+006.856000e+023.000000e+000.000000e+004.583000e-01
75%0.000000e+002.000000e+001.860000e+021.000000e+000.000000e+002.000000e+007.100000e+011.172000e+031.000000e+001.000000e+002.132000e+011.851000e+034.900000e+014.700000e+011.500000e+030.000000e+001.909750e-010.000000e+000.000000e+000.000000e+000.000000e+001.976000e+035.000000e+001.495000e+037.407000e-01
max2.200000e+013.300000e+016.616000e+035.300000e+016.400000e+018.000000e+011.010000e+022.170000e+037.200000e+012.000000e+011.094000e+032.237000e+031.000000e+021.000000e+025.910000e+033.900000e+014.071000e+041.800000e+013.823000e+031.200000e+015.000000e+002.578000e+042.360000e+022.013000e+031.000000e+00

직관적인 데이터 부터 살펴보자

Kill & Damage

train_df['kills'].quantile(0.99)
7.0
  • kill 의 평균은 0.9이고 상위 25% 이상부터 1킬, 그 이하는 1킬도 달성하지 못한다. 상위 1%는 7킬이상
  • 최대값은 72로 나와있으나 이는 아웃라이어, 불법프로그램을 이용한 유저의 데이터 같다.
kill_data = train_df.copy()
kill_data.loc[kill_data['kills'] >= 8] = '8+'

plt.figure(figsize=(8,6))
plt.title("Kill Count")

sns.countplot(kill_data['kills'].astype('str').sort_values())
plt.show()
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
  warnings.warn(

output_17_1

sns.jointplot(data=train_df, x='winPlacePerc', y='kills')
plt.show()

output_18_0

  • 킬수와 승리는 상관관계가 존재한다. 흥미로운 점은 한번도 킬을 하지 않고 우승을 달성한 유저이다.
  • 솔로의 경우 이는 불가능하고 이른바 ‘버스’탄다고 하는, 좋은 팀을 만나거나 꾸려서 승리를 달성한 경우이다.

  • 데미지의 경우 킬과 밀접한 상관이 있을 수밖에 없다.
df = train_df.copy()
df = df[df['kills']==0]

sns.distplot(df['damageDealt'])
plt.show()
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
  warnings.warn(msg, FutureWarning)

output_21_1

df = df[df['winPlacePerc'] == 1.0]
sns.histplot(data=df, x='damageDealt')
<AxesSubplot:xlabel='damageDealt', ylabel='Count'>

output_22_1

  • 데미지 경우 한번도 사살하지 못한 유저의 경우 데미지도 주지 못한 경우가 대부분임을 알 수 있다.
  • ‘버스’를 탄 유저를 보았을때 데미지를 주지못한, 제대로 편승한 유저가 대부분임을 알 수 있다.
df_0 = df[df['damageDealt']==0]

a = len(df)
b = len(df_0)
print(a, b)
16666 4709
df_0['matchType'].value_counts()
squad-fpp           2674
squad               1211
solo                 313
duo-fpp              295
duo                  122
normal-squad-fpp      70
crashfpp               7
normal-duo-fpp         6
normal-squad           3
crashtpp               3
normal-duo             1
normal-solo            1
solo-fpp               1
flaretpp               1
normal-solo-fpp        1
Name: matchType, dtype: int64
  • 16666명의 유저는 0킬로 우승 그중 4770명은 유저 한 번 맞추지도 않고 우승을 했다.
  • 4770명의 경우 대부분 스쿼드를 통해 우승을 달성. 솔로는 불법프로그램 이용일까?
sns.jointplot(data=train_df, x='winPlacePerc', y='headshotKills')
plt.show()

output_27_0

  • 헤드샷 킬과 승리 역시 상관관계가 있어보인다.
  • 헤드샷 30명 이상은 불법프로그램이용으로 유추해볼 수 있지 않을까 싶다.

Heal & Boost

  • 치료와 부스트 아이템 사용은 직관적으로 우승과 연결지을 순 없지만 우승을 위해서 오래 플레이해야하고 많은 교전을 거쳐야 한다는 일반상식을 적용하였을때 충분한 상관관계가 있어 보인다.
  • 아웃라이어 제거를 위해 상위 1% 이상 data는 제거 한다.

  • heals의 평균은 1.3으로 유저는 1.3의 치료아이템을 게임당 평균 사용하며 절반이상은 하나도 사용하지 않는데 이는 교전해보지도 못하고 죽는 유저의 수와 게임 특성상 교전 후 살아남은 유저만이 치료아이템을 사용할 수 있기 때문이다.
  • boosts의 평균은 1.1으로 유저는 1.1의 부스트아이템을 게임당 평균 사용하며 절반 이상은 하나도 사용하지 않는다.
  • boosts는 heals와 비슷한 양상을 보인다. 나머지 체력의 회복 및 교전 전 반응속도를 빠르게 하기 위해 boosts아이템을 사용하는데 이 역시 ‘교전’과 연관되기 때문에 한번도 킬을 달성하지 못하고 데미지도 주지 못하는 유저가 많은 게임 특성상 낮은 사용율을 보인다.
a = train_df['heals'].quantile(0.99)
b = train_df['boosts'].quantile(0.99)
print(a, b)
12.0 7.0
sns.jointplot(data=train_df, x='winPlacePerc', y='heals', color='purple')
plt.show()

output_33_0

sns.jointplot(data=train_df, x="winPlacePerc", y="boosts", color="yellow")
plt.show()

output_34_0

  • heals 와 boosts 모두 양의 상관관계를 보인다

Walk & Ride & Swim

  • walksDistance의 평균은 1154m를 뛰며 편차가 1200m 정도로 크다. 게임 초반 이동없이 교전이 이루어지는 특성 때문인가?
  • rideDistance의 평균은 606m이며 50%이상은 차를 이용하지 않았다. 우승과 차량이용간 관계를 밝히는 것 역시 도움이 될 듯 하다.
  • swimDistance의 평균은 4.5m이며 대부분은 수영을 하지 않았다. 섬이란 특성상 물은 섬 주변 혹은 강줄기에 희박하게 분포한다는 특성 때문이다.
sns.jointplot(data=train_df, x='winPlacePerc', y='walkDistance', color='Green', kind='hex')
plt.show()

output_38_0

sns.jointplot(data=train_df, x='winPlacePerc', y='walkDistance', color='Green')
plt.show()

output_39_0

len(train_df[train_df['walkDistance'] == 0.0])
99603
len(train_df[train_df['walkDistance'] <= 100.0])
834241
  • 분명한 양의 상관관계 존재. 많은 유저가 게임 초반, 교전이 이루어질때 사망함을 알 수 있다.
  • 한번도 움직이지 않은(혹은 못한) 유저는 10만명정도, 100m라는 짧은 거리(교전 초반)를 이동하고 죽은 유저는 83만정도로 약 20%에 해당한다.

Solo, Duo, Squad

  • 배틀그라운드 게임의 경우 유저는 게임을 혼자 즐기거나 팀을 꾸려 즐길 수 있는데 팀의 경우 (2인, 4인) 두 가지 팀의 양상이 존재한다.
  • 팀 게임에 혼자 참여하여 즐기는 경우가 있지만 그럴 경우는 적어 분석에 제외하고 게임 양상을 위와 같이 세 가지로 나누어 분석하는 것이 의미있어 보인다.
  • matchType 컬럼 경우 이벤트 matchType도 존재하기에 게임 당 그룹수로 나누는것이 합리적으로 보인다.
solos = train_df[train_df['numGroups']>50]
duos = train_df[(train_df['numGroups']>25) & (train_df['numGroups']<=50)]
squads = train_df[train_df['numGroups']<=25]
a = len(solos)
b = len(duos)
c = len(squads)
a1 = len(solos) / len(train_df) * 100
b1 = len(duos) / len(train_df) * 100
c1 = len(squads) / len(train_df) * 100
print ('솔로게임은', a, '건이고 전체의', round(a1,2),'%이다.')
print ('듀오게임은', b, '건이고 전체의', round(b1,2),'%이다.')
print ('스쿼드게임은', c, '건이고 전체의', round(c1,2),'%이다.')
솔로게임은 709111 건이고 전체의 15.95 %이다.
듀오게임은 3295326 건이고 전체의 74.1 %이다.
스쿼드게임은 442529 건이고 전체의 9.95 %이다.
fig,axes = plt.subplots(figsize =(18,10))
sns.pointplot(data=solos, x='kills',y='winPlacePerc',color='black')
sns.pointplot(data=duos, x='kills',y='winPlacePerc',color='red')
sns.pointplot(data=squads, x='kills',y='winPlacePerc',color='blue')
plt.grid()
plt.show()

output_48_0

  • 솔로와 듀오 게임의 양상은 비슷하고 킬수와 승리관계가 명확하다.
  • 스쿼드 게임의 경우 킬과 승리가 상관관계가 있지만 8킬이상은 그렇게 유의미해 보이지 않다. 게임특성상 스쿼드 게임의 경우 난장이 되는 경우가 많기 때문인듯 싶다.

전처리

train_df.columns
Index(['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'],
      dtype='object')
train_df.drop(['Id', 'groupId', 'matchId', 'longestKill', 'matchDuration', 'matchType', 'maxPlace',
       'numGroups', 'rankPoints','teamKills','weaponsAcquired', 'winPoints'], axis=1, inplace=True)
train_df.columns
Index(['assists', 'boosts', 'damageDealt', 'DBNOs', 'headshotKills', 'heals',
       'killPlace', 'killPoints', 'kills', 'killStreaks', 'revives',
       'rideDistance', 'roadKills', 'swimDistance', 'vehicleDestroys',
       'walkDistance', 'winPlacePerc'],
      dtype='object')
train_df['walkDistance'].quantile(0.99)
4396.0
train_df = train_df.loc[train_df['kills'] <= 7.0]
train_df = train_df.loc[train_df['assists'] <= 3.0]
train_df = train_df.loc[train_df['boosts'] <= 7.0]
train_df = train_df.loc[train_df['damageDealt'] <= 777.0]
train_df = train_df.loc[train_df['DBNOs'] <= 5.0]
train_df = train_df.loc[train_df['headshotKills'] <= 3.0]
train_df = train_df.loc[train_df['heals'] <= 12.0]
train_df = train_df.loc[train_df['killStreaks'] <= 3.0]
train_df = train_df.loc[train_df['rideDistance'] <= 6966.0]
train_df = train_df.loc[train_df['swimDistance'] <= 123.0]
train_df = train_df.loc[train_df['walkDistance'] <= 4396.0]
train_df.sample(10)
assistsboostsdamageDealtDBNOsheadshotKillshealskillPlacekillPointskillskillStreaksrevivesrideDistanceroadKillsswimDistancevehicleDestroyswalkDistancewinPlacePerc
257642901156.800013501100.000.00160.50.4362
206533401131.6010113201103384.000.001415.00.6154
8681160020.400006912310000.000.00222.70.4021
12095460027.510006600000.000.00901.90.4255
81911800100.001003211911100.000.00136.30.1739
294304401349.001111303100.000.00221.00.3125
201717500156.602003314371110.000.00580.70.4074
238632701268.70100201029220379.200.00706.60.3958
36285401133.400023112861100.000.001407.00.6392
2629328010.000007800000.000.00238.60.2449
plt.figure(figsize=(12, 12))
sns.heatmap(train_df.corr(), annot=True, fmt= '.1f')
plt.show()

output_56_0

  • 상관성을 살펴보면 타겟 변수인 ‘winPlacePerc’과 상관성이 높은 변수는 ‘walkDistance’,’boosts’, ‘kills’,’damageDealt’,’heals’순이며 역으로 ‘killplace’와도 상관이 있다.(높을수록 낮은숫자)
  • ‘heals’와 ‘boosts’간의 상관성, ‘walkDistance’와 ‘boosts’,’heals’간의 상관성이 돋보인다. ‘boosts’와 ‘kills’간의 상관성이 높다. 이는 교전 전, 교전에 임하기 위해 boost아이템 사용하는 양상과 관련이 깊어 보인다.
# 성능이 좋지 않아 출력이 안됨..

sns.set()
cols = ['winPlacePerc', 'walkDistance', 'boosts', 'kills', 'damageDealt', 'killPlace']
sns.pairplot(train_df[cols], height = 2.5)
plt.show()
train_df.columns
Index(['assists', 'boosts', 'damageDealt', 'DBNOs', 'headshotKills', 'heals',
       'killPlace', 'killPoints', 'kills', 'killStreaks', 'revives',
       'rideDistance', 'roadKills', 'swimDistance', 'vehicleDestroys',
       'walkDistance', 'winPlacePerc'],
      dtype='object')
from sklearn.preprocessing import StandardScaler

X = train_df[['assists', 'boosts', 'damageDealt', 'DBNOs', 'headshotKills', 'heals',
       'killPlace', 'killPoints', 'kills', 'killStreaks', 'revives',
       'rideDistance', 'roadKills', 'swimDistance', 'vehicleDestroys',
       'walkDistance']]

scaler = StandardScaler()
scaler.fit(X)
X_scaled = scaler.transform(X)
X_scaled = pd.DataFrame(X_scaled, index=X.index, columns=X.columns)
y = train_df['winPlacePerc']
X.head()
assistsboostsdamageDealtDBNOsheadshotKillshealskillPlacekillPointskillskillStreaksrevivesrideDistanceroadKillsswimDistancevehicleDestroyswalkDistance
0000.000006012410000.000000.000244.80
10091.470005700000.0045011.0401434.00
21068.000004700000.000000.000161.80
30032.900007500000.000000.000202.70
400100.000004501100.000000.00049.75

학습-테스트 데이터 분리

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
from xgboost import XGBRegressor

model_reg = XGBRegressor()
model_reg.fit(X_train, y_train)
XGBRegressor(base_score=0.5, booster='gbtree', colsample_bylevel=1,
             colsample_bynode=1, colsample_bytree=1, gamma=0, gpu_id=-1,
             importance_type='gain', interaction_constraints='',
             learning_rate=0.300000012, max_delta_step=0, max_depth=6,
             min_child_weight=1, missing=nan, monotone_constraints='()',
             n_estimators=100, n_jobs=4, num_parallel_tree=1, random_state=0,
             reg_alpha=0, reg_lambda=1, scale_pos_weight=1, subsample=1,
             tree_method='exact', validate_parameters=1, verbosity=None)
from sklearn.metrics import mean_absolute_error, mean_squared_error
from math import sqrt
pred = model_reg.predict(X_test)
print(mean_absolute_error(y_test, pred))
print(sqrt(mean_squared_error(y_test, pred)))
0.07068083815399646
0.09807103337560909
plt.figure(figsize=(7,7))
plt.scatter(x=y_test, y=pred, alpha=0.005)
plt.plot([0,1], [0,1], 'r-')

plt.xlabel('Real')
plt.ylabel('Predict')
Text(0, 0.5, 'Predict')

output_67_1

  • 전체적으로 overestimate 하는 경향이 있다.
  • 실제점수는 0.0이지만 괜찮은 점수를 획득했다고 예측하는 경향이 있다.
  • 넓은 게임 맵 특성상, 킬-데미지를 주지않고도 많이 돌아다니는 유저들을 통해 해당 예측값이 나온듯 하다. walkDistance가 중요한 변수이기에