[OPGG] 롤 나의 게임 정보 불러오기
Updated:
1. 나의 게임 정보
그동안 배웠던 내용을 토대로 나의 롤 플레이 정보를 불러와 여러 지표를 확인할 것이다.
# ploty 패키지 설치
# !pip install plotly
import pandas as pd
import numpy as np
import requests
import time
# 시각화 패키지
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# 경고창 무시
import warnings
warnings.filterwarnings("ignore")
1.1 accountId
# API 키 갱신 확인 후 사용
api_key = ##직접 입력##
# 소환사 이름
summonerName = "Romg2"
summoner_url = f"https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/{summonerName}?api_key={api_key}"
summoner_r = requests.get(summoner_url)
# 나의 accountId
encryptedAccountId = summoner_r.json()['accountId']
- 개발자 홈페이지에 대한 이해가 조금 필요한데 여기선 소환사 이름을 통해 해당 유저의 accountId를 불러왔다.
1.2 gameId stack
beginIndex = 0
# 매치 정보 (지수표현으로 나오지 않는지 확인)
my_matchid = np.array([], dtype=int)
while True:
match_url = f"https://kr.api.riotgames.com/lol/match/v4/matchlists/by-account/{encryptedAccountId}?api_key={api_key}&beginIndex={beginIndex}"
match_r = requests.get(match_url)
# stop 조건: 불러온 json 파일의 length
if len(pd.json_normalize(match_r.json()['matches'])) == 0:
break
# 한번에 100의 매치 정보
temp_matchid = pd.DataFrame(match_r.json()['matches'])["gameId"]
# gameid stack
my_matchid = np.concatenate([my_matchid, temp_matchid.values])
# start index 변경
beginIndex += 100
# RATE LIMITS 피하기
time.sleep(1)
-
앞서 얻은 accountId를 URL에 입력하여 해당 accountId가 플레이한 matchid를 가져오는 과정이다.
-
여기서 전체 플레이를 불러오기 위해 while문을 사용하여 더 이상 불러올 수 없으면 멈춘다.
-
아래는 라이엇에서 개인용 API KEY로 불러올 수 있는 LIMIT에 대한 설명이다.
RATE LIMITS
20 requests every 1 seconds(s)
100 requests every 2 minutes(s)
- 이에 따라
time.sleep()
을 설정해두었다.
1.3 match information stack
my_game = pd.DataFrame()
for i in my_matchid:
gameid = i
game_url = f"https://kr.api.riotgames.com/lol/match/v4/matches/{gameid}?api_key={api_key}"
game_r = requests.get(game_url)
# 10명의 대전 정보
temp_game = pd.json_normalize(game_r.json()['participants'])
# 나의 participantid 확인
summoner_lst = pd.json_normalize(game_r.json()['participantIdentities'])
me = summoner_lst[summoner_lst['player.accountId'] == encryptedAccountId]
# 나의 대전 정보
temp_game = temp_game[temp_game['participantId'] == int(me['participantId'])]
# 추가 정보 (게임 종류, 게임 시간)
temp_game["subType"] = game_r.json()["queueId"]
temp_game["gameLength"] = game_r.json()["gameDuration"]
# 대전 정보 stack
my_game = my_game.append(temp_game)
# RATE LIMITS 피하기
time.sleep(1)
-
이제 각 matchid에 대한 게임 정보를 데이터 프레임으로 만드는 과정이다.
-
게임 판수가 많다면 시간이 매우 오래걸린다.
-
한 게임당 1초의 sleep을 주었으니 2,000게임이면 대략 30분 정도 걸릴 것이다.
-
불러오는 과정에서 게임 종류나 시간은 participants에 포함된 데이터가 아니어서 다시 돌렸다.
-
처음부터 원하는 컬럼에 대해 파악하고 테스트 한 후 잘 짜두어야 한다.
# # 시간이 오래걸리므로 csv로 저장
# my_game.to_csv(f"Day02_02_{summonerName}_log.csv", index=False)
- 시간이 오래 걸리기에 csv 파일로 저장하였다.
2. 데이터 전처리
2.1 데이터 로드
# 저장한 csv load
my_game2 = pd.read_csv(f"Day02_02_{summonerName}_log.csv")
my_game2.head()
participantId | teamId | championId | spell1Id | spell2Id | stats.participantId | stats.win | stats.item0 | stats.item1 | stats.item2 | ... | timeline.goldPerMinDeltas.20-30 | timeline.csDiffPerMinDeltas.30-end | timeline.csDiffPerMinDeltas.20-30 | timeline.xpDiffPerMinDeltas.30-end | timeline.xpDiffPerMinDeltas.20-30 | timeline.damageTakenPerMinDeltas.30-end | timeline.damageTakenPerMinDeltas.20-30 | timeline.damageTakenDiffPerMinDeltas.30-end | timeline.damageTakenDiffPerMinDeltas.20-30 | highestAchievedSeasonTier | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10 | 200 | 126 | 32 | 4 | 10 | False | 3070 | 1036 | 1036 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 4 | 100 | 164 | 32 | 4 | 4 | False | 3143 | 6630 | 3111 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 5 | 100 | 517 | 32 | 4 | 5 | False | 3066 | 6656 | 3158 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | 10 | 200 | 115 | 7 | 4 | 10 | False | 3157 | 4637 | 6653 | ... | 446.0 | 0.05 | 1.15 | -148.5 | -49.65 | 1081.5 | 721.4 | 282.45 | -102.45 | NaN |
4 | 9 | 200 | 163 | 7 | 4 | 9 | True | 1056 | 2003 | 0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 143 columns
-
드디어 나의 플레이 정보를 위와 같이 확인 할 수 있다.
-
컬럼이 너무 많으니 원하는 컬럼만 사용해보자.
# 특정 컬럼만 사용
col_lst = ["subType", "teamId", "gameLength", "championId",
"stats.win", "stats.kills", "stats.deaths", "stats.assists",
"timeline.lane"]
my_game3 = my_game2[col_lst]
# 랭크(420)만 사용
my_game3 = my_game3[my_game3["subType"].isin([420])]
print(my_game3.shape)
(871, 9)
my_game3.head()
subType | teamId | gameLength | championId | stats.win | stats.kills | stats.deaths | stats.assists | timeline.lane | |
---|---|---|---|---|---|---|---|---|---|
3 | 420 | 200 | 2482 | 115 | False | 14 | 10 | 15 | BOTTOM |
4 | 420 | 200 | 192 | 163 | True | 0 | 1 | 0 | NONE |
11 | 420 | 100 | 1402 | 412 | True | 1 | 3 | 8 | BOTTOM |
12 | 420 | 100 | 1712 | 163 | True | 4 | 6 | 8 | MIDDLE |
13 | 420 | 100 | 1322 | 50 | True | 4 | 4 | 6 | MIDDLE |
- 총 871판의 랭크 게임 데이터 정보에 대해 일부 컬럼을 확인하였다.
my_game3.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 871 entries, 3 to 1499
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 subType 871 non-null int64
1 teamId 871 non-null int64
2 gameLength 871 non-null int64
3 championId 871 non-null int64
4 stats.win 871 non-null bool
5 stats.kills 871 non-null int64
6 stats.deaths 871 non-null int64
7 stats.assists 871 non-null int64
8 timeline.lane 871 non-null object
dtypes: bool(1), int64(7), object(1)
memory usage: 62.1+ KB
- 컬럼별 데이터 타입 확인
my_game3.isnull().sum()
subType 0
teamId 0
gameLength 0
championId 0
stats.win 0
stats.kills 0
stats.deaths 0
stats.assists 0
timeline.lane 0
dtype: int64
- 결측값은 없으나 다시하기 여부나 포지션이 제대로 입력되었는지 확인이 필요하다.
2.2 다시하기, 포지션 확인
my_game3["stats.win"].value_counts()
False 446
True 425
Name: stats.win, dtype: int64
-
다시하기가 UNKNOWN으로 있으리라 생각했는데 없다.
-
아마 다시하기가 False에 포함되어 있지 않을까?
# 4분 이내 승리여부
my_game3[my_game3["gameLength"] < 240]
subType | teamId | gameLength | championId | stats.win | stats.kills | stats.deaths | stats.assists | timeline.lane | |
---|---|---|---|---|---|---|---|---|---|
4 | 420 | 200 | 192 | 163 | True | 0 | 1 | 0 | NONE |
603 | 420 | 200 | 203 | 203 | True | 0 | 0 | 0 | NONE |
1042 | 420 | 200 | 194 | 99 | True | 0 | 0 | 0 | NONE |
1065 | 420 | 100 | 197 | 266 | False | 0 | 0 | 0 | NONE |
1107 | 420 | 200 | 198 | 22 | False | 0 | 0 | 0 | NONE |
1122 | 420 | 100 | 201 | 266 | True | 0 | 0 | 0 | NONE |
1145 | 420 | 200 | 197 | 235 | True | 0 | 0 | 0 | NONE |
-
다시하기 기준 3분과 투표시간 1분을 고려해서 확인하였을 때 승리 여부에서 True, False가 혼합되어 있다.
-
더불어서 포지션의 경우 NONE으로 입력된 경우가 있다.
-
분리할 방법을 못 찾겠어서 일반적인 서렌 기준 15분 보다 작은 데이터는 삭제하자.
-
이렇게 보면 다시하기 투표를 한 팀에 속하는 경우 패배, 아닌 경우는 승리가 아닐까?
print(my_game3["timeline.lane"].unique())
print(my_game3["timeline.lane"].value_counts())
['BOTTOM' 'NONE' 'MIDDLE' 'TOP' 'JUNGLE']
BOTTOM 533
NONE 97
JUNGLE 87
MIDDLE 77
TOP 77
Name: timeline.lane, dtype: int64
-
우선 서폿, 원딜 구분이 안되고 NONE이 97개로 생각보다 많다.
-
추후 챔피언 이름을 붙혀서 일부 예외말고는 분류가 잘 되있다면 수기 분류
2.3 컬럼 수정
# KDA 추가하기
def cal_KDA(df):
# perfect KDA는 death에 1을 추가
if df["stats.deaths"] == 0:
adjust = 1
else:
adjust = 0
KDA = (df["stats.kills"] + df["stats.assists"]) / (df["stats.deaths"] + adjust)
return KDA
my_game3["K/D/A"] = my_game3.apply(lambda x: cal_KDA(x), axis=1)
my_game3.head()
subType | teamId | gameLength | championId | stats.win | stats.kills | stats.deaths | stats.assists | timeline.lane | K/D/A | |
---|---|---|---|---|---|---|---|---|---|---|
3 | 420 | 200 | 2482 | 115 | False | 14 | 10 | 15 | BOTTOM | 2.9 |
4 | 420 | 200 | 192 | 163 | True | 0 | 1 | 0 | NONE | 0.0 |
11 | 420 | 100 | 1402 | 412 | True | 1 | 3 | 8 | BOTTOM | 3.0 |
12 | 420 | 100 | 1712 | 163 | True | 4 | 6 | 8 | MIDDLE | 2.0 |
13 | 420 | 100 | 1322 | 50 | True | 4 | 4 | 6 | MIDDLE | 2.5 |
- KDA는 데스가 0인 경우는 분모를 1로 설정
# 챔피언 정보 가져오기
champion_constant = requests.get("http://ddragon.leagueoflegends.com/cdn/11.15.1/data/ko_KR/champion.json")
champion_df = pd.DataFrame(champion_constant.json()['data']).T[['key','id']]
# 데이터 타입 변경
champion_df["key"] = champion_df["key"].astype(int)
# 챔피언 이름 추가
my_game4 = pd.merge(my_game3, champion_df, how = 'left', left_on = 'championId', right_on = 'key')
# 컬럼명 변경
rename_col_lst = {
"subType": "type",
"teamId": "side",
"id": "champion",
"gameLength": "length",
"stats.win": "win",
"timeline.lane": "position",
"stats.kills": "K",
"stats.deaths":"D",
"stats.assists":"A",
"K/D/A": "KDA"
}
my_game4.rename(columns = rename_col_lst, inplace = True)
# 게임종류, 진영 이름 적어주기, 승패여부 int, 게임시간 분단위
my_game4["type"] = my_game4["type"].apply(lambda x: "Rank" if x == 420 else "Aram")
my_game4["side"] = my_game4["side"].apply(lambda x: "Blue" if x == 100 else "Red")
my_game4["win"] = my_game4["win"].astype(int)
my_game4["length"] = my_game4["length"] / 60
# 일부 컬럼 추출
my_game4 = my_game4[rename_col_lst.values()]
my_game4
type | side | champion | length | win | position | K | D | A | KDA | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Rank | Red | Ziggs | 41.366667 | 0 | BOTTOM | 14 | 10 | 15 | 2.900000 |
1 | Rank | Red | Taliyah | 3.200000 | 1 | NONE | 0 | 1 | 0 | 0.000000 |
2 | Rank | Blue | Thresh | 23.366667 | 1 | BOTTOM | 1 | 3 | 8 | 3.000000 |
3 | Rank | Blue | Taliyah | 28.533333 | 1 | MIDDLE | 4 | 6 | 8 | 2.000000 |
4 | Rank | Blue | Swain | 22.033333 | 1 | MIDDLE | 4 | 4 | 6 | 2.500000 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
866 | Rank | Red | Kaisa | 25.616667 | 1 | BOTTOM | 0 | 7 | 4 | 0.571429 |
867 | Rank | Blue | Varus | 26.516667 | 1 | BOTTOM | 2 | 2 | 14 | 8.000000 |
868 | Rank | Blue | Lucian | 23.083333 | 1 | MIDDLE | 11 | 1 | 6 | 17.000000 |
869 | Rank | Blue | Ashe | 34.483333 | 1 | BOTTOM | 11 | 8 | 11 | 2.750000 |
870 | Rank | Red | Karma | 19.166667 | 0 | NONE | 0 | 6 | 4 | 0.666667 |
871 rows × 10 columns
-
컬럼명과 값들을 보기 쉽게 편집 (게임종류의 경우 이미 랭크만 뽑아서 안써도 상관 없음)
-
여기서 2번째 index 탈리야 정보가 게임길이가 3분 정도인데 이겼다고 확인
-
op.gg에 Romg2 검색시 탈리야로 최근 20게임 검색시 다시하기로 되어있음을 확인 가능하다.
2.4 다시하기, 포지션 수정
print(f"삭제 전 게임 수: {my_game4.shape[0]}")
my_game4 = my_game4[my_game4["length"] > 15]
print(f"삭제 후 게임 수: {my_game4.shape[0]}")
삭제 전 게임 수: 871
삭제 후 게임 수: 858
location = my_game4["position"].unique()
for i in location:
print(i, "\n", my_game4[my_game4["position"] == f"{i}"]["champion"].unique(), "\n")
BOTTOM
['Ziggs' 'Thresh' 'Ashe' 'Samira' 'Karma' 'Swain' 'Ezreal' 'Varus'
'Taliyah' 'Aphelios' 'Sivir' 'Lucian' 'Senna' 'MissFortune' 'Xayah'
'Jinx' 'Jhin' 'Alistar' 'Zyra' 'Braum' 'Xerath' 'Kaisa' 'Neeko' 'Lux'
'Tristana' 'Jax' 'Caitlyn' 'Twitch' 'Kalista' 'Sona' 'Vayne' 'Morgana'
'Blitzcrank' 'Maokai' 'Yasuo' 'Irelia']
MIDDLE
['Taliyah' 'Swain' 'Varus' 'Ezreal' 'Senna' 'Sylas' 'TwistedFate' 'Ahri'
'Tristana' 'Gnar' 'Jinx' 'Corki' 'Xayah' 'Jhin' 'Malzahar' 'Lucian'
'Ashe' 'Caitlyn' 'Sivir' 'Zilean' 'Garen' 'Leblanc' 'Diana' 'Gragas'
'Quinn' 'Aatrox' 'MissFortune' 'Ryze' 'Qiyana' 'Akali' 'Irelia' 'Poppy'
'Kaisa']
TOP
['Camille' 'Viego' 'Sylas' 'Gnar' 'Gangplank' 'Poppy' 'Jayce' 'Ornn'
'Kled' 'Quinn' 'Kayle' 'Kalista' 'Aatrox' 'Karma' 'DrMundo' 'Lucian'
'Vayne' 'Garen' 'Vladimir' 'Mordekaiser' 'Nasus' 'Jax' 'Fiora' 'Kaisa']
NONE
['Kalista' 'Senna' 'Samira' 'Varus' 'Swain' 'Xayah' 'Thresh' 'Ashe'
'Sivir' 'MissFortune' 'Ahri' 'Aatrox' 'Jax' 'Tristana' 'Kaisa' 'Gnar'
'Nasus' 'Renekton' 'Kindred' 'Ekko' 'Jhin' 'Ezreal' 'Caitlyn' 'Twitch'
'Jinx' 'Taliyah' 'Lucian' 'Vladimir' 'Aphelios' 'Alistar' 'Garen' 'Leona'
'Corki' 'Kayle' 'Irelia' 'Diana' 'Vayne' 'Pyke' 'Karma']
JUNGLE
['Viego' 'Varus' 'Swain' 'Diana' 'LeeSin' 'Jax' 'Ekko' 'Gnar' 'Graves'
'Lillia' 'Renekton' 'Nidalee' 'Gragas' 'JarvanIV' 'Kindred' 'Shyvana'
'Elise' 'Kayn' 'RekSai' 'Qiyana' 'Taliyah' 'Fiora' 'Sylas' 'DrMundo'
'Ashe']
-
어느 정도 맞는거 같기도 한데.. 정글 스웨인이나 애쉬는 도저히 아닌거 같다.
-
포지션은 아쉽지만 우선 버리기로 결정
# 포지션 컬럼 삭제
my_game4.drop(columns="position", inplace=True, axis=1)
2.5 게임 시간 구간
# 게임 시간 5분 단위로 (ex 15분이상 20분 미만)
len1 = (my_game4["length"] //5 *5).astype(str).str[:2]
len2 = (my_game4["length"] //5 *5 + 5).astype(str).str[:2]
my_game4["length_dummy"] = len1 + "_" + len2 + "min"
my_game4.head()
type | side | champion | length | win | K | D | A | KDA | length_dummy | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Rank | Red | Ziggs | 41.366667 | 0 | 14 | 10 | 15 | 2.9 | 40_45min |
2 | Rank | Blue | Thresh | 23.366667 | 1 | 1 | 3 | 8 | 3.0 | 20_25min |
3 | Rank | Blue | Taliyah | 28.533333 | 1 | 4 | 6 | 8 | 2.0 | 25_30min |
4 | Rank | Blue | Swain | 22.033333 | 1 | 4 | 4 | 6 | 2.5 | 20_25min |
5 | Rank | Red | Camille | 29.533333 | 0 | 7 | 6 | 2 | 1.5 | 25_30min |
- 게임 시간 구간별 승률을 확인하기 위해 5분 단위로 잘라서 생성
my_game4["length_dummy"].value_counts()
25_30min 237
30_35min 200
20_25min 196
35_40min 89
15_20min 84
40_45min 37
45_50min 14
50_55min 1
Name: length_dummy, dtype: int64
my_game4 = my_game4[my_game4["length_dummy"] != "50_55min"]
- 50분 이상 55분 미만 게임은 하나밖에 없어 편의상 제거하였다.
3. 지표 확인
3.1 진영, 게임 시간별 승률
# KDA 추가하기
def cal_KDA2(df):
# perfect KDA는 death에 1을 추가
if df["D"] == 0:
adjust = 1
else:
adjust = 0
KDA = (df["K"] + df["A"]) / (df["D"] + adjust)
return KDA
# 승률
def ratio(x):
return x.sum() / x.count() * 100
# 그룹별 집계
def group_statistic(df, group_lst, sort=False):
# 판수, 승리수, 승률
temp = df.groupby(group_lst)["win"].agg({'count', "sum", ratio}).reset_index()
# 패배수 추가
temp["lc"] = temp["count"] - temp["sum"]
# 그룹별 KDA 추가
kda = df.groupby(group_lst).sum().apply(lambda x: cal_KDA2(x), axis=1).values
temp["kda"] = kda
# 컬럼 순서 지정
re = {"count":"total_count", "sum":"win_count", "lc":"lose_count", "ratio":"win_rate", "kda":"KDA"}
temp = temp.rename(columns=re)
temp = temp[group_lst + list(re.values())]
# 정렬 옵션
if sort != False:
temp = temp.sort_values(by=[sort], ascending=False)
return temp
-
지정한 그룹별로 승률 및 KDA 계산하는 함수
-
KDA의 경우 기존 KDA(게임별)를 평균 내면 안될 것 같아 새로 산출
group_statistic(my_game4, ["type"], sort="win_rate")
type | total_count | win_count | lose_count | win_rate | KDA | |
---|---|---|---|---|---|---|
0 | Rank | 857 | 417 | 440 | 48.65811 | 2.655069 |
-
우선 전체 랭크 승률인데 50%가 안된다..
-
매치별 날짜를 확인 못하겠는데 2019시즌까지는 플레였는데 그 후로 쭉 내리막으로 골드여서 그런게 아닐까?
-
매치별 날짜와 티어가 확인 된다면 좋을 듯한데 못 찾았다.
group_statistic(my_game4, ["side"], sort="win_rate")
side | total_count | win_count | lose_count | win_rate | KDA | |
---|---|---|---|---|---|---|
1 | Red | 433 | 218 | 215 | 50.346420 | 2.656510 |
0 | Blue | 424 | 199 | 225 | 46.933962 | 2.653634 |
-
진영별로는 Blue 진영에 비해 Red 진영이 판수가 더 많고 승률도 높다.
-
예상과 반대로 Red 진영 승률이 더 높다.
group_statistic(my_game4, ["length_dummy"])
length_dummy | total_count | win_count | lose_count | win_rate | KDA | |
---|---|---|---|---|---|---|
0 | 15_20min | 84 | 38 | 46 | 45.238095 | 1.967213 |
1 | 20_25min | 196 | 105 | 91 | 53.571429 | 2.381842 |
2 | 25_30min | 237 | 101 | 136 | 42.616034 | 2.344715 |
3 | 30_35min | 200 | 106 | 94 | 53.000000 | 3.001775 |
4 | 35_40min | 89 | 43 | 46 | 48.314607 | 2.984823 |
5 | 40_45min | 37 | 19 | 18 | 51.351351 | 3.296578 |
6 | 45_50min | 14 | 5 | 9 | 35.714286 | 2.649254 |
-
게임 시간별로는 20분 이상 25분 미만에서 승률이 가장 좋았다.
-
초반 승률이 낮고 후반 승률이 높은 등의 추세를 보고 싶었는데 특별한 패턴은 안보인다.
-
전처리를 잘못해서 그럴까, 진짜 이럴까?
group_statistic(my_game4, ["side", "length_dummy"])
side | length_dummy | total_count | win_count | lose_count | win_rate | KDA | |
---|---|---|---|---|---|---|---|
0 | Blue | 15_20min | 32 | 15 | 17 | 46.875000 | 1.867347 |
1 | Blue | 20_25min | 101 | 57 | 44 | 56.435644 | 2.485333 |
2 | Blue | 25_30min | 117 | 47 | 70 | 40.170940 | 2.213355 |
3 | Blue | 30_35min | 100 | 50 | 50 | 50.000000 | 2.911765 |
4 | Blue | 35_40min | 44 | 19 | 25 | 43.181818 | 3.167247 |
5 | Blue | 40_45min | 22 | 8 | 14 | 36.363636 | 3.535211 |
6 | Blue | 45_50min | 8 | 3 | 5 | 37.500000 | 2.512500 |
7 | Red | 15_20min | 52 | 23 | 29 | 44.230769 | 2.034247 |
8 | Red | 20_25min | 95 | 48 | 47 | 50.526316 | 2.278075 |
9 | Red | 25_30min | 120 | 54 | 66 | 45.000000 | 2.475649 |
10 | Red | 30_35min | 100 | 56 | 44 | 56.000000 | 3.096539 |
11 | Red | 35_40min | 45 | 24 | 21 | 53.333333 | 2.813725 |
12 | Red | 40_45min | 15 | 11 | 4 | 73.333333 | 3.016529 |
13 | Red | 45_50min | 6 | 2 | 4 | 33.333333 | 2.851852 |
- 진영, 게임 시간별 승률도 확인
3.2 챔피언별 승률
# 15판 이상 플레이한 챔피언 승률
temp = group_statistic(my_game4, ["champion"], sort="win_rate")
temp[(temp["total_count"] >= 15)]
champion | total_count | win_count | lose_count | win_rate | KDA | |
---|---|---|---|---|---|---|
62 | Swain | 19 | 14 | 5 | 73.684211 | 4.379747 |
58 | Senna | 95 | 52 | 43 | 54.736842 | 3.311203 |
4 | Aphelios | 33 | 18 | 15 | 54.545455 | 2.287234 |
13 | Ekko | 24 | 13 | 11 | 54.166667 | 3.445652 |
39 | Lucian | 43 | 22 | 21 | 51.162791 | 2.528571 |
27 | Jinx | 28 | 14 | 14 | 50.000000 | 2.582781 |
69 | Varus | 38 | 19 | 19 | 50.000000 | 3.170732 |
64 | Taliyah | 31 | 15 | 16 | 48.387097 | 3.006289 |
57 | Samira | 23 | 11 | 12 | 47.826087 | 2.640000 |
15 | Ezreal | 67 | 32 | 35 | 47.761194 | 2.741433 |
73 | Xayah | 24 | 11 | 13 | 45.833333 | 2.566372 |
5 | Ashe | 60 | 27 | 33 | 45.000000 | 2.286127 |
26 | Jhin | 29 | 13 | 16 | 44.827586 | 3.078740 |
43 | MissFortune | 30 | 12 | 18 | 40.000000 | 2.868571 |
28 | Kaisa | 26 | 7 | 19 | 26.923077 | 1.793333 |
-
15판 이상 플에이한 챔피언의 승률이다.
-
세나는 95판이나 플레이했는데 승률도 준수한 반면 카이사 괜히 해서 승률 엄청 까먹은 것을 확인 가능하다.
3.3 시각화
# 챔피언별 승률 (전체 플레이 수 상위 10개)
temp = group_statistic(my_game4, ["champion"], sort="total_count")
top_10_champ = temp.iloc[:10,0].values
temp = group_statistic(my_game4, ["side", "champion"], sort="total_count")
temp2 = temp[temp["champion"].isin(top_10_champ)]
fig1 = px.bar(temp2, x="win_rate", y="champion", color="side",
barmode="group", orientation="h",
hover_data=["total_count", "win_count", "lose_count", "KDA"], hover_name="side")
# 게임 시간별 승률
temp = group_statistic(my_game4, ["side", "length_dummy"])
fig2 = px.bar(temp, x="length_dummy", y="win_rate", color="side",
barmode="group",
hover_data=["total_count", "win_count", "lose_count", "KDA"], hover_name="side")
# 진영별 승률
temp3 = my_game4.copy()
temp3["win"] = temp3["win"].apply(lambda x: "승리" if x==1 else "패배")
temp3_blue = temp3[temp3["side"]=="Blue"]
temp3_red = temp3[temp3["side"]=="Red"]
fig3 = px.pie(temp3_blue, names="win", hole = 0.5)
fig3.update_traces(textposition="inside", textinfo="percent+label")
fig4 = px.pie(temp3_red, names="win", hole = 0.5)
fig4.update_traces(textposition="inside", textinfo="percent+label")
# subplot type 설정 (2x3)
fig = make_subplots(rows=2, cols=3, shared_xaxes=False,
specs=[ [{'type':'xy',"rowspan": 2}, {'type':'xy','colspan':2}, None],
[None, {'type':'domain'}, {'type':'domain'}] ])
trace1_1 = fig1['data'][0]
trace1_2 = fig1['data'][1]
trace2_1 = fig2['data'][0]
trace2_2 = fig2['data'][1]
trace3 = fig3['data'][0]
trace4 = fig4['data'][0]
fig.add_trace(trace1_1, row=1, col=1)
fig.add_trace(trace1_2, row=1, col=1)
fig.add_trace(trace2_1, row=1, col=2)
fig.add_trace(trace2_2, row=1, col=2)
fig.add_trace(trace3, row=2, col=2)
fig.add_trace(trace4, row=2, col=3)
fig.update_layout(
title_text="Win Rate",
height=600,width=1000,
showlegend=False,
plot_bgcolor='white'
)
fig.show()
fig.write_html("Day02_02_check_me.html")
-
plotly
패키지를 이용한 시각화로 마우스를 올리면 진영과 승률, 판수, 승수, KDA 등이 확인 가능 -
오른쪽 아래 도넛 차트 2가지는 진영별로 승률을 나타냈으나 현재 시각화가 깔끔하지 못함
-
조금 더 깔끔하게 수정 필요
4. 추후 파악요소?
어느정도 살펴보았을 때 아래 부분을 파악하면 더 재밌을 것 같습니다
-
다시하기 기준
-
포지션 분류 기준
-
게임 날짜 확인
-
티어 확인
-
시각화 보완
Leave a comment