[Kaggle/캐글]롤(lol) 챌린저 리그 오브젝트 영향 분석_1
https://shinminyong.tistory.com/11
롤 API를 이용해 데이터 분석을 진행하려고 정보를 찾아보던 중 kaggle에 2020년도 챌린저 데이터를 올려주신 분이 있어 해당 데이터를 참조하여 kaggle에서 분석을 진행했습니다.
https://www.kaggle.com/jinhyunkwon/used-decision-tree-object-control
분석은 의사결정나무(Decision Tree)를 이용하여 진행하였습니다.
분석하려 한 정보는 매치 내에서 처음으로 가져간 오브젝트가 게임의 승리에 얼마나 영향을 줬는가.
에 대해서 분석을 진행하였습니다.
가볍게 말하는 첫드래곤을 먹으면 이긴다 혹은 첫 타워를 가져가면 승리한다 같은 말이 정말로 실효성이 있는 것인지 확인해보고 싶었습니다.
먼저 설명드리고 싶은 부분은 저도 공부를 해나가고 있는 입장이라 이 분석, 해석이 틀린 부분이 있을 수 있습니다.
글을 보고 그렇구나, 하는 부분보다는 그럴 수도 있구나 혹은 이 부분은 수정이 필요하겠다. 하는 부분을 염두해주시고 봐주시길 부탁드리겠습니다.
가장 먼저 캐글에서 파일 데이터를 불러오는 기본 코드부터 시작하겠습니다.
# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All"
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
해당 코드를 실행하게 되면 해당 datasets에 저장되어 있는 csv 파일의 경로를 모두 불러오게 됩니다.
아래와 같이 불러와진 datasets의 경로는 그대로 불러와서 사용할 수 있습니다.
현재 해당 데이터는 매치 승과 패로 구분되어 있고, 저는 승패를 모두 합친 데이터를 분석하고 싶어 우선 두 개의 datasets를 하나로 합쳐줬습니다.
df1 = pd.read_csv('/kaggle/input/league-of-legendslol-ranked-games-2020-ver1/match_loser_data_version1.csv')
df2 = pd.read_csv('/kaggle/input/league-of-legendslol-ranked-games-2020-ver1/match_winner_data_version1.csv')
df = pd.concat([df1,df2], ignore_index=True)
df.head
그리고 정상적으로 데이터가 불러와졌는지 .head를 이용하여 데이터를 불러왔습니다.
내용이 길어 일부만 가져왔습니다.
이 중에서 숫자형으로 이루어진 타워 킬, 전령 킬, 바론 킬 같은 숫자형 데이터는 모두 제거하였습니다.
퍼스트 블러드, 퍼스트 바론, 퍼스트 타워 등의 요인에 대해서만 분석하기 위함입니다.
(이 부분은 추후 로지스틱스 회귀분석이나 Tensor Flow를 이용한 머신러닝으로 예측 분석을 해볼 예정입니다.)
df = df.drop(["towerKills","inhibitorKills","baronKills",
"dragonKills","vilemawKills","riftHeraldKills",
"dominionVictoryScore","gameId","teamId","Unnamed: 0",
"bans"], axis=1)
df.head
그리고 정상적으로 삭제가 되었는지 확인하기 위해 한 번 더 .head를 사용하였습니다.
정상적으로 삭제된 것을 확인하였습니다.
데이터의 승패 정보 당 각 항목의 평균치를 확인했습니다.
df.groupby('win').mean()
해당 자료만 봐도 평균적으로 퍼블을 가져간 팀이 이긴 평균은 60%, 타워를 먼저 가져 간 팀이 이긴 평균은 72%에 달하는 것을 확인할 수 있습니다.
데이터에 공백 값이 있을 경우 0으로 반환하였습니다.
반환하기 전에 데이터를 확인했을 때 공백인 값이 12개뿐이었기 때문에 큰 영향을 줄 수 없다고 판단하고 0으로 부여하였습니다.
df = df.fillna(0)
df.isnull().sum().sum()
이후 각 요소들 간의 상관관계를 분석하기 위해서 상관 분석을 먼저 진행하였습니다.
만약 각 요소들의 상관관계가 높다면 한 항목이 다른 항목에 영향을 끼쳤을 수 있기 때문에 상관관계를 우선 검증하였습니다.
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
plt.figure(figsize=(10,10))
sns.heatmap(df.corr(),cmap='coolwarm',annot=True)
plt.show()
각 항목별 상관도는 크게 높은 항목이 없기 때문에 정상 진행을 해도 될 것으로 판단하였습니다.
이후 각 데이터를 boolean 타입에서 숫자형으로 변환하기 위해서 데이터 변환을 했습니다.
df['win'] = df['win'].replace({'Win':1, 'Fail':0})
df["firstBlood"] = df["firstBlood"].astype(int)
df["firstTower"] = df["firstTower"].astype(int)
df["firstInhibitor"] = df["firstInhibitor"].astype(int)
df["firstDragon"] = df["firstDragon"].astype(int)
df["firstBaron"] = df["firstBaron"].astype(int)
df["firstRiftHerald"] = df["firstRiftHerald"].astype(int)
df.groupby('win').mean()
위와 동일하게 평균을 불러와서 정상여부를 판단했습니다.
의사결정 나무 분석을 위해서 sklearn의 DecisionTreeClassifier와 plot_tree를 호출하였습니다.
이후 win을 y값으로 놓기 위해 x에서 win칼럼을 드롭한 후 y로 변경하였습니다.
최소 데이터 분류 기준은 4만 건으로 plt.show 했습니다.
건수를 조금 높게 잡았기 때문에 depth는 별도로 지정하지 않았습니다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import plot_tree
X = df.drop(['win'], axis=1)
y = df['win']
xname = X.columns
yname = ['fail','win']
c_tree = DecisionTreeClassifier(min_samples_split=40000,random_state=0)
c_tree.fit(X, y)
plt.figure(figsize=(50,10))
plot_tree(c_tree, feature_names=xname, class_names=yname, filled=True, fontsize=12)
plt.show()
그 결과 아래와 같은 Decision Tree가 생성되었습니다.
부분적으로 주석을 조금 달아보도록 하겠습니다.
우선 위에서 true와 false를 모두 1,0으로 변환하였기 때문에 여기서 <= 0.5에 대해서는 단순하게 생각하면 그 조건을 달성하지 못한 것이라고 볼 수 있습니다.
분기를 내려오면 아래와 같은 해석으로 이해할 수 있습니다.
이긴 경기중 95.6%는 첫 억제기를 먼저 밀고 첫 드래곤을 먹었으며, 첫타워 역시 먹었습니다.
이긴 경기중 91.9%는 첫 억제기를 먼저 밀고 첫 드래곤을 먹었으며, 첫 타워는 실패하였습니다.
이긴 경기중 87.3%는 첫 억제기를 먼저 밀고 첫 드래곤을 먹지 못했습니다.
이긴 경기중 61.7%는 첫 억제기를 먹지 못했지만 첫타워는 먼저 먹었고, 첫 드래곤 역시 먹었습니다.
이긴 경기중 33.8%는 첫 억제기를 먹지 못했고 첫타워는 먹었지만, 첫 드래곤은 먹지 못했습니다.
여기서부터 승률이 확연히 차이 나기 시작합니다.
억제기를 먼저 민다는 것은 게임이 중반 이상으로 흘러갔다는 것을 뜻합니다.
그런데 이 억제기를 먹기 전 초반 단계에서 첫 타워, 그리고 첫 용을 가져가지 못한다면 억제기를 가져갈 확률 역시 낮아진다고도 볼 수 있습니다.
다만 역기서 흥미로운 점은 첫 억제기를 먼저 밀지 못하고 첫 타워를 먼저 먹지 못하더라도 첫 바론을 먼저 가져가게 될 경우 승률이 46.7%가 된다는 점입니다.
이는 후반에 바론의 역할이 확실히 크다는 것을 반증합니다.
12.4%로 승리한 게임은 억제기도 먼저 밀지 못하고, 첫 타워도 먹지 못하고, 첫 바론도 뺏겼지만 그 게임의 퍼블을 먼저 가져갈 경우입니다.
9.8%와 6.6%는 퍼블조차 가져가지 못한 상황에서 첫 드래곤을 먹었느냐 먹지 못하였느냐로 나뉘는 것인데 실질적으로 앞선 바론, 타워, 억제기 등을 챙겨가지 못한다면 사실상 드래곤의 유무는 3.2%p 정도의 차이밖에 만들지 못합니다.
이 데이터를 검증하면서 가장 유의하게 봤던 점은 후반 바론의 역할입니다.
LCK리그를 보다 보면 '후반 바론 싸움에서 어떻게 될지 모른다', '바론이라는 변수가 있다.'
라는 말을 많이 들을 수 있습니다.
이는 데이터로도 실질적으로 보인다고 할 수 있습니다.
억제기를 먼저 밀리고, 첫 타워가 먼저 밀린 상황에서도 첫 바론을 챙기는 것 만으로 46.7%의 승률을 가져갈 수 있다는 것은 첫 바론의 중요도가 굉장히 높다는 것을 뜻합니다.
실제로 첫 바론을 실패했을 경우 46.7%의 승률은 12.4%까지 단번에 떨어지게 됩니다.
datasets을 제공해주신 kaggle Minyong Shin님(https://www.kaggle.com/gyejr95)에게 다시 한번 감사를 드리며 다음에는 해당 데이터의 바론, 드래곤, 타워의 개수에 따른 승률 분석을 로지스틱 회귀분석과 텐서 플로우를 통해서 추가 분석해보도록 하겠습니다.
위의 분석이나 해석이 틀린 점이 있다면 많은 지적과 첨언 부탁드리겠습니다.