본문 바로가기
study

리그 오브 레전드 승패 예측

by 나는야오리 2020. 4. 13.

API활용 예시를 찾다가 우연히 흥미로운 프로젝트가 있어 필사해보았다. 출처는 아래 남겨두었으며 해당 블로그에서 코드도 함께 공유하고 있으므로 참고하면 된다. 라이엇의 게임 리그 오브 레전드 데이터를 활용하였다. 자세한 코드는 생략했다.

1. 라이엇 API 키 발급
2. 데이터 분석

1. 라이엇 API 키 발급

라이엇 개발자 사이트에 접속하여 회원가입을 하면 API키를 발급받을 수 있다. 일시적으로 발급하는 키라서 최대 허용치가 정해져 있다. 따라서 분석 중에 간혹 데이터 허용치를 초과하여 오류가 나는 경우가 있다. 바로 재발급 받을 수 있다. 귀찮다면 API 키를 정식으로 신청하는 방법도 있다.

# 필요한 모듈 설치 
import requests
import pandas as pd
import json
import re

# API 연결
api_key = '발급 받은 API'
id_url = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/" + "게임닉네임" +'?api_key=' + api_key
r = requests.get(id_url)

Response가 200이라면 정상적으로 작동한다는 뜻이다.

2. 데이터 분석

2.1. 데이터 로드

앞서 말한 라이엇 개발자 사이트에서 APIs 탭에서는 각종 API와 이를 불러오기 위해서 필요한 내용을 제공하고 있다. 필요에 따라서 원하는 데이터를 불러오면 된다. 여기서는 13시즌의 레벨이 그랜드마스터인 계정의 매치정보를 불러왔다. 우선 블로그에서 공유한 코드대로 매치 정보를 불러왔고 중간 저장했다.

그리고 match_info_df2 데이터의 gameID를 통해 매치 정보를 불러온다.

match_fin = pd.DataFrame()
for i in range(len(match_info_df2)):
    try:           
        api_url='https://kr.api.riotgames.com/lol/match/v4/matches/' + str(match_info_df2['gameId'].iloc[i]) + '?api_key=' + api_key
        r = requests.get(api_url)

        while r.status_code == 429:
            time.sleep(2)
            #time.sleep를 꼭 해줘야함 안그러면 request 잦은 사용으로 블랙리스트가 됨
            api_url='https://kr.api.riotgames.com/lol/match/v4/matches/' + str(match_info_df2['gameId'].iloc[i]) + '?api_key=' + api_key
            r = requests.get(api_url)
        
        mat = pd.DataFrame(list(r.json().values()), index=list(r.json().keys())).T
        match_fin = pd.concat([match_fin,mat])

    except:
        pass

2.2. 결측치 제거

이제 분석할 데이터가 취합이 되었으니 본격적으로 분석을 해보자. status를 제외하고 각 행에 정확히 20개씩 결측치가 있다. 이상하다 싶어 확인해보니 API를 불러올때 생기는 오류같다. 특정 행의 모든 값이 결측치로 찍혀나왔다. 그렇게 20행이 존재했다. 

따라서 결측치를 포함한 행을 제거해주었다. 아래 코드에서 reset_index() 부터는 인덱싱을 위한 것으로 아직 미숙한 부분이라 참고만 하시길

data = data[data['gameId'].isnull() == False].reset_index().drop(['index'],axis=1)

2.3. Feature engineering

분석하고자 하는 특성만 추출하여 데이터셋을 구축하고자 한다. 아래 코드는 출처 블로그에 자세한 설명과 함께 나온다. 약간 다른 점은 데이터프레임을 결합하는 과정에서 오류가 생겨 해결하지 못하고 나누어서 진행했다.

#챔피언아이디를 제외하고 딕셔너리를 뽑는다
a_ls = list(data['teams'])

#team1
team1_df = pd.DataFrame()
for i in range(len(a_ls)):
    try:
        a_ls[i][0].pop('bans',None)
        team1 = pd.DataFrame(list(a_ls[i][0].values()),index = list(a_ls[i][0].keys())).T
        team1_df = team1_df.append(team1)
    except:
        pass
    
team1_df.index = range(len(team1_df))

#team2
team2_df = pd.DataFrame()
error = []
for i in range(len(a_ls)):
    try:
        a_ls[i][1].pop('bans',None)
        team2 = pd.DataFrame(list(a_ls[i][1].values()),index = list(a_ls[i][1].keys())).T
        team2_df = team2_df.append(team2)
    except:
        pass
        
    
team2_df.index = range(len(team2_df))
team1_df = pd.concat([team1_df,data['gameDuration']],axis=1)
team2_df = pd.concat([team2_df,data['gameDuration']],axis=1)

data_team = pd.concat([team1_df, team2_df])
data_team = data_team.reset_index().drop(['index'],axis=1)
data_team.to_csv('./data_team.csv')

data_team

한 쪽이 이기면 한쪽이 지는 것이므로 A팀의 정보만 취합한 후, 라벨링을 해주었다. 아래 T/F 값을 가지는 칼럼을 숫자로 변환 시키는 과정은 생략한다. 

2.4. modeling

블로그에서 사용한 분석 모델 중 정확도가 가장 높은 Xgboost를 사용해보았다.

# train과 test로 데이터를 0.75 : 0.25 비율로 나눈다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(data_team1, np.array(data_team[data_team['teamId']==100]['win'].map(dict_winner).tolist()), test_size=0.25, stratify=np.array(data_team[data_team['teamId']==100]['win'].map(dict_winner).tolist()), random_state=123456)

from xgboost import XGBClassifier
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot

#xgb로 학습시키기 위해서는 dtypes이 단순하게 int형식이면 안된다. 따라서 데이터 형식을 float로 변환시켜줘야함
X_train[['towerKills', 'inhibitorKills', 'baronKills', 'dragonKills', 'vilemawKills', 'riftHeraldKills', 'dominionVictoryScore', 'gameDuration']] = X_train[['towerKills', 'inhibitorKills', 'baronKills', 'dragonKills', 'vilemawKills', 'riftHeraldKills', 'dominionVictoryScore', 'gameDuration']].astype('float')

#xgb로 학습시키기 위해서는 dtypes이 단순하게 int형식이면 안된다. 따라서 데이터 형식을 float로 변환시켜줘야함
X_test[['towerKills', 'inhibitorKills', 'baronKills', 'dragonKills', 'vilemawKills', 'riftHeraldKills', 'dominionVictoryScore', 'gameDuration']] = X_test[['towerKills', 'inhibitorKills', 'baronKills', 'dragonKills', 'vilemawKills', 'riftHeraldKills', 'dominionVictoryScore', 'gameDuration']].astype('float')

xgb_model = XGBClassifier()
xgb_model.fit(X_train,y_train)
y_pred = xgb_model.predict(X_test)

print('테스트 정확도 = ' + str(accuracy_score(y_test,y_pred)))#정확도 계산

정확도는 0.943으로 매우 높은 수치가 나왔다. 그리고 어느 변수가 중요했는지 변수 중요도도 알아보았다.

import matplotlib
import matplotlib.pyplot as plt

def plot_feature_importance(model) :
    n_features = data_team1.shape[1]
    plt.barh(range(n_features), model.feature_importances_, align='center')
    plt.yticks(np.arange(n_features), X_train.columns)
    plt.xlabel("특성중요도")
    plt.ylabel("특성")
    plt.ylim(-1, n_features)
    
plot_feature_importance(rf)

변수 중요도 그래프

마치며

게임 시간이 가장 중요한 변수로 나온 것이 의문이다. 그 외 오브젝트나 타워제거가 중요한 것은 너무 뻔한 결과라 아쉬움이 많이 남는다. API 문서를 둘러보고 전형적이지 않은 데이터가 있다면 피쳐로 활용하면 좋을 것 같다. 중간에 누락된 코드로 삽질하는 시간이 길었지만 그만큼 유익했다.

출처 

*Reference : https://shinminyong.tistory.com/11?category=839096

 

라이엇 api를 활용한 리그오브레전드 데이터 수집

안녕하세요. 이번 포스팅은 평소에 즐겨하던 "리그오브레전드"의 게임 데이터를 이용하여 분석해보는 시간을 갖도록 하겠습니다. 그전에 리그오브레전드 데이터를 수집해야하는데요, 리그오브레전드를 즐겨하거나..

shinminyong.tistory.com

'study' 카테고리의 다른 글

지도학습 : 커널 서포트 벡터 머신  (0) 2020.04.15
지도학습 : 결정트리의 앙상블  (0) 2020.04.15
리그 오브 레전드 승패 예측  (0) 2020.04.13
Youtube 댓글 크롤링  (0) 2020.04.05
지도학습 : 나이브베이즈  (0) 2020.03.30
지도학습 : 선형 모델  (0) 2020.03.29

댓글0