분석 배경
이전에 입사 사전과제로 분석했던 내용인데, 원하는 만큼의 퀄리티가 나오진 않았습니다.
천 만 행이 넘는 큰 JSON 파일을 분석해본 경험도 처음이었고, 배틀그라운드에 대한 기본적인 지식도 부족했던 것 같네요.
특히 일반 유저들과 프로 선수들의 경기가 매우 큰 차이가 있다는 것을 알고, 엎고 다시 진행했던 것이 시간을 많이 날려먹었습니다.
총 분석 기간은 8일 정도였고, 부족한 분석이었지만 올려둡니다.
# 패키지 불러오기
# api 요청
import requests
import json
# 데이터 자료형 및 분석도구
import pandas as pd
import numpy as np
# 시각화 패키지
import matplotlib as mlp
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from matplotlib import patheffects
%matplotlib inline
sns.set()
# 스케일링
from sklearn.preprocessing import MinMaxScaler
# 시간
import time
from datetime
# 진행 사항 확인
from tqdm import tqdm
# PUBG 분석 도구
from chicken_dinner.pubgapi import PUBG
from chicken_dinner.constants import COLORS
from chicken_dinner.constants import map_dimensions
# api key 설정 및 데이터 요청
api_key = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2ZGNjNzNhMC0yMDk5LTAxMzctYjNjMi0wMmI4NjZkNzliOGIiLCJpc3MiOiJnYW1lbG9ja2VyIiwiaWF0IjoxNTUxNjk2NzA2LCJwdWIiOiJibHVlaG9sZSIsInRpdGxlIjoicHViZyIsImFwcCI6InB1YmctYmVzdC1wbGF5In0.Oz7GmLsWF7038XIO4vKd5sivhLreOnizxTNcARAEFQs'
headers = {'accept': 'application/vnd.api+json',
'Authorization': f'Bearer {api_key}'}
url = "https://api.pubg.com/tournaments/kr-pkl18"
r = requests.get(url, headers=headers)
league_json = r.json()
league_json
{'data': {'type': 'tournament',
'id': 'kr-pkl18',
'relationships': {'matches': {'data': [{'type': 'match',
'id': '277295d2-e148-4749-92e8-7c00f3a23219'},
{'type': 'match', 'id': '7cac694a-575f-46ad-8101-e3226cfbaf10'},
{'type': 'match', 'id': 'ab7c47b7-5d1f-465f-8843-44b552809881'},
{'type': 'match', 'id': '7428419d-81ec-45a9-ba4b-8a30f809e226'},
{'type': 'match', 'id': 'f169b923-612f-42f5-a45b-7b2e4221d92d'},
...]}}},
'included': [{'type': 'match',
'id': '59dc37a9-aee1-4bdb-8326-f46335f0033f',
'attributes': {'createdAt': '2019-02-07T05:49:39Z'}},
{'type': 'match',
'id': 'b5add322-a6b4-4617-8e40-ee5188bbb894',
'attributes': {'createdAt': '2019-01-04T12:24:53Z'}},
{'type': 'match',
'id': '7eb3b00b-8321-4605-8991-56835da566ae',
'attributes': {'createdAt': '2018-12-01T11:09:27Z'}},
{'type': 'match',
'id': '318052e5-da5e-41ee-8a71-40aabf75a553',
'attributes': {'createdAt': '2018-11-23T11:54:53Z'}},
{'type': 'match',
'id': 'af2e8a26-419a-40e4-b7ae-9bad7789a487',
'attributes': {'createdAt': '2018-11-21T10:42:51Z'}},
...],
'links': {'self': 'https://api.pubg.com/tournaments/kr-pkl18'},
'meta': {}}
# kr-pkl18 데이터 matchId 저장
matchId_dict = {match['attributes']['createdAt']: match['id'] for match in league_json['included']}
matchId_df = pd.DataFrame(sorted(matchId_dict.items(), key=lambda x: x[0]),
columns=['createdAt', 'matchId'])
# Erangel 맵 데이터만 사용
erangelMatch_df = match_df[match_df['mapName'] == 'Erangel_Main'].loc[:90]
# Rangers 팀이 참가한 데이터만 사용
pubg = PUBG(api_key, shard='tournament')
matchId_rangers = []
for matchId in tqdm(erangelMatch_df['matchId']):
current_match = pubg.match(matchId)
telemetry = current_match.get_telemetry()
telemetry.player_names()
findCount = (pd.Series(telemetry.player_names()).str.find('Rangers') > -1).sum()
if findCount > 0:
matchId_rangers.append(matchId)
# 경기 후의 stats 정보를 데이터프레임 안의 데이터프레임으로 저장
# 비효율적. 이번 분석에서는 stats 정보를 이용하지 않았음
# apply lambda를 위한 함수 (시리즈 변환)
def ParticipantsMerge(row):
participants = pd.Series(row['attributes']['stats'])
participants['id'] = row['id']
return participants
headers = {'accept': 'application/vnd.api+json'}
match_df = pd.DataFrame()
participants_df = pd.DataFrame()
for matchId in matchId_rangers:
url = f'https://api.pubg.com/shards/tournament/matches/{matchId}'
r = requests.get(url, headers=headers)
while r.status_code != 200:
time.sleep(3)
r = requests.get(url, headers=headers)
data = r.json()
stats_series = pd.Series(data['data']['attributes'])
stats_series['matchId'] = matchId
included = pd.DataFrame(data['included'])
rosters = included[included['type'] == 'roster']
rosters = rosters.apply(lambda row: [row['attributes']['stats']['rank'],
row['attributes']['stats']['teamId'],
row['attributes']['won'],
pd.DataFrame(row['relationships']['participants']['data']),
row['id']], axis=1)
rosters = pd.DataFrame(list(rosters), columns=['rank', 'teamId', 'won', 'participants', 'id'])
participants = included[included['type'] == 'participant']
participants = participants.apply(lambda row: ParticipantsMerge(row), axis=1)
participants = participants.reset_index(drop=True)
participants = participants.drop(['killPoints', 'killPointsDelta', 'lastKillPoints', 'lastWinPoints',
'mostDamage', 'rankPoints', 'winPoints', 'winPointsDelta'],
axis=1, errors='ignore')
rosters['participants'] = rosters['participants'].map(lambda x: x.merge(participants))
stats_series['rosters'] = rosters
participants_df = participants_df.append(participants, ignore_index=True, sort=False)
match_df = match_df.append(stats_series, ignore_index=True, sort=False)
match_df = match_df.drop(['stats', 'titleId', 'shardId', 'tags', 'gameMode', 'isCustomMatch'], axis=1)
# 교전 횟수, 첫 차량 탑승, 화이트&블루존과의 상대적 거리 구하기
attack_df = pd.DataFrame()
teamCount = {}
whiteCenter_df = pd.DataFrame()
blueBorder_df = pd.DataFrame()
playerMove_df = pd.DataFrame()
firstVehicle_df = pd.DataFrame()
for matchId in matchId_rangers:
current_match = pubg.match(matchId) #chicken_dinner 라이브러리 이용
telemetry = current_match.get_telemetry()
positions = telemetry.player_positions()
circles = telemetry.circle_positions()
players = np.array(telemetry.player_names())
rosters = players[np.where(pd.Series(players).str.find('Rangers') > -1)[0]] # {Team}의 존 상대적 거리
whiteCenter_means = {}
blueBorder_means = {}
playerMove_means = {}
for player in rosters:
curpos = np.array(positions[player])
while len(circles['white']) < len(curpos): curpos = curpos[:-1]
length = len(curpos)
start = np.where(curpos[:, 3] < 30000)[0][0]
curpos = curpos[start:]
whites = np.array(circles['white'])[start:length]
blues = np.array(circles['blue'])[start:length]
white_xDiff = (whites[:, 1] - curpos[:, 1]); white_yDiff = (whites[:, 2] - curpos[:, 2])
blue_xDiff = (blues[:, 1] - curpos[:, 1]); blue_yDiff = (blues[:, 2] - curpos[:, 2])
phases = np.where(whites[1:, 4] - whites[:-1, 4] < 0)[0] + 1 # 단계 인덱싱 구하기
phases = np.append(phases, len(whites))
white_means = []
blue_means = []
moves = []
pre = 0
for phase in phases: #단계마다 공식 계산
cur_white_xDiff = white_xDiff[pre:phase]; cur_white_yDiff = white_yDiff[pre:phase]
cur_blue_xDiff = blue_xDiff[pre:phase]; cur_blue_yDiff = blue_yDiff[pre:phase]
whiteCenter_diff = np.sqrt(np.square(cur_white_xDiff) + np.square(cur_white_yDiff)) / whites[pre:phase, 4]
blueBorder_diff = (blues[pre:phase, 4] - np.sqrt(np.square(cur_blue_xDiff) + np.square(cur_blue_yDiff))) \
/ blues[pre:phase, 4]
white_means.append(whiteCenter_diff.mean())
blue_means.append(blueBorder_diff.mean())
moves.append((whiteCenter_diff[1:] - whiteCenter_diff[:-1]).mean())
pre = phase
whiteCenter_means[player] = white_means
blueBorder_means[player] = blue_means
playerMove_means[player] = moves
whiteCenter_df = pd.concat(
[whiteCenter_df, pd.DataFrame.from_dict(whiteCenter_means, orient='index').T.mean(axis=1)],
axis=1, sort=False)
blueBorder_df = pd.concat(
[blueBorder_df, pd.DataFrame.from_dict(blueBorder_means, orient='index').T.mean(axis=1)],
axis=1, sort=False)
playerMove_df = pd.concat(
[playerMove_df, pd.DataFrame.from_dict(playerMove_means, orient='index').T.mean(axis=1)],
axis=1, sort=False)
# 게임 시작 시간
startTime = pd.to_timedelta(telemetry.started()[telemetry.started().find('T')+1:-1])
endTime = telemetry.events[-1].timestamp # 마지막 이벤트 시간
endTime = (pd.to_timedelta(endTime[endTime.find('T')+1:-1]) - startTime).total_seconds()
circles = telemetry.circle_positions()
whites = np.array(circles['white'])
phases = np.where(whites[1:, 4] - whites[:-1, 4] != 0)[0] + 1
phaseTimes = whites[phases, 0]
phaseTimes = np.append(phaseTimes, endTime)
attackLog = telemetry.filter_by('log_player_attack') # 교전 (공격한 경우) 데이터
attackData = [(log['attacker']['name'],
(pd.to_timedelta(log.timestamp[log.timestamp.find('T')+1:-1]) - startTime).total_seconds())
for log in attackLog if pd.to_timedelta(log.timestamp[log.timestamp.find('T')+1:-1]) > startTime]
attackData = pd.DataFrame(attackData, columns=['name', 'time'])
attackData['teamName'] = attackData['name'].str.extract(r'([0-9A-Za-z]+)\_') # 팀명 추출
attackData['phase'] = np.nan
for i in range(len(phaseTimes)-1):
attackData.loc[(attackData['time'] < phaseTimes[i+1]) & (attackData['time'] > phaseTimes[i]), 'phase'] = i+1
attack_df = pd.concat([attack_df, attackData], axis=0)
for team in attackData['teamName'].unique():
try:
teamCount[team] += 1
except KeyError:
teamCount[team] = 1
vehicles = telemetry.filter_by('log_vehicle_ride') # 차량 탑승 데이터
firstVehicle = {}
used_teamId = []
for vehicle in vehicles: # 팀에서 첫 차량 탑승 경우만 구하기
if vehicle['vehicle']['vehicle_type'] != 'WheeledVehicle' or \
vehicle['character']['name'] in firstVehicle.keys() or \
vehicle['character']['name'][:vehicle['character']['name'].find('_')] in used_teamId: continue
firstVehicle[vehicle['character']['name'][:vehicle['character']['name'].find('_')]] = \
((pd.to_timedelta(vehicle.timestamp[vehicle.timestamp.find('T')+1:-1]) - startTime).total_seconds(), \
vehicle['character']['location']['x'], mapy - vehicle['character']['location']['y'])
used_teamId.append(vehicle['character']['name'][:vehicle['character']['name'].find('_')])
firstVehicle_df = pd.concat([firstVehicle_df, pd.DataFrame(firstVehicle)], axis=1, sort=False)
firstVehicle_df = firstVehicle_df.T
firstVehicle_df.columns = ['time', 'x', 'y']
firstVehicle_df['teamName'] = firstVehicle_df.index
firstVehicle_team = pd.concat([firstVehicle_df[['teamName', 'time']].groupby('teamName').mean(),
firstVehicle_df[['teamName', 'time']].groupby('teamName').count()], axis=1, sort=False)
firstVehicle_team.columns = ['time', 'count']
firstVehicle_team = firstVehicle_team[firstVehicle_team['count'] > 10]
teamCount = pd.DataFrame(pd.Series(teamCount))
teamCount.columns = ['name']
teamCount.index.name = 'teamName'
teamAttack_df = attack_df[['teamName', 'phase', 'name']].groupby(['teamName', 'phase']).count()
teamAttack_df['countMean'] = (teamAttack_df / teamCount).round()
teamAttack_df = teamAttack_df.drop('name', axis=1)
teamAttack_df['phasePercent'] = (teamAttack_df / teamAttack_df.sum(level=0)).round(4) * 100
teamAttack_df.loc[['Rangers', 'Hunters', 'EntusA', 'EntusF'], :]
countMean | phasePercent | ||
---|---|---|---|
teamName | phase | ||
EntusA | 1.0 | 40.0 | 17.02 |
2.0 | 58.0 | 24.68 | |
3.0 | 44.0 | 18.72 | |
4.0 | 49.0 | 20.85 | |
5.0 | 29.0 | 12.34 | |
6.0 | 10.0 | 4.26 | |
7.0 | 2.0 | 0.85 | |
9.0 | 3.0 | 1.28 | |
EntusF | 1.0 | 29.0 | 11.65 |
2.0 | 48.0 | 19.28 | |
3.0 | 24.0 | 9.64 | |
4.0 | 49.0 | 19.68 | |
5.0 | 34.0 | 13.65 | |
6.0 | 41.0 | 16.47 | |
7.0 | 17.0 | 6.83 | |
8.0 | 6.0 | 2.41 | |
9.0 | 1.0 | 0.40 | |
Hunters | 1.0 | 15.0 | 5.03 |
2.0 | 24.0 | 8.05 | |
3.0 | 38.0 | 12.75 | |
4.0 | 63.0 | 21.14 | |
5.0 | 60.0 | 20.13 | |
6.0 | 49.0 | 16.44 | |
7.0 | 42.0 | 14.09 | |
8.0 | 7.0 | 2.35 | |
Rangers | 1.0 | 16.0 | 6.04 |
2.0 | 34.0 | 12.83 | |
3.0 | 43.0 | 16.23 | |
4.0 | 64.0 | 24.15 | |
5.0 | 41.0 | 15.47 | |
6.0 | 37.0 | 13.96 | |
7.0 | 21.0 | 7.92 | |
8.0 | 8.0 | 3.02 | |
9.0 | 1.0 | 0.38 |
# 첫 차량 탑승 지역 시각화
fig = plt.figure(figsize=(10, 10), dpi=100)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis("off")
img_path = '/home/idea_demo/LPoint/KYH/BattleGround/Maps/Erangel_Main_High_Res.jpg'
img = mpimg.imread(img_path)
ax.imshow(img, extent=[0, mapx, 0, mapy])
xy = np.vstack([firstVehicle_df.x,firstVehicle_df.y])
z = gaussian_kde(xy)(xy) # 데이터 몰려있는 지역 확인
ax.scatter(firstVehicle_df.x, firstVehicle_df.y,
marker="o", c=z, edgecolor="k", s=45, linewidths=0.8, zorder=20)
<matplotlib.collections.PathCollection at 0x7fcc2ede4d68>
# 경기 이동 경로 시각화
current_match = pubg.match(matchId_rangers[2]) #1주차 4라운드 경기
telemetry = current_match.get_telemetry()
positions = telemetry.player_positions()
circles = telemetry.circle_positions()
whites = np.array(circles['white'])
whites[:, 2] = mapy - whites[:, 2]
phases = np.where(whites[1:, 4] - whites[:-1, 4] != 0)[0] + 1
fig = plt.figure(figsize=(10, 10), dpi=100)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis("off")
img_path = '/home/idea_demo/LPoint/KYH/BattleGround/Maps/Erangel_Main_High_Res.jpg'
img = mpimg.imread(img_path)
ax.imshow(img, extent=[0, mapx, 0, mapy])
for phase in phases:
white_circle = plt.Circle((whites[phase][1], whites[phase][2]), whites[phase][4],
edgecolor="w", linewidth=0.7, fill=False, zorder=5)
ax.add_patch(white_circle)
startTime = pd.to_timedelta(telemetry.started()[telemetry.started().find('T')+1:-1])
unequips = telemetry.filter_by('log_item_unequip')
landing_locations = {unequip['character']['name']:
(unequip['character']['location']['x'], mapy - unequip['character']['location']['y'],
(pd.to_timedelta(unequip.timestamp[unequip.timestamp.find('T')+1:-1]) - startTime).total_seconds(),
unequip['character']['team_id'])
for unequip in unequips if unequip['item']['item_id'] == 'Item_Back_B_01_StartParachutePack_C'}
landing_locations = pd.DataFrame(landing_locations).T.reset_index()
landing_locations.columns = ['name', 'x', 'y', 'time', 'teamId']
landing_locations['teamId'] = landing_locations['teamId'].astype('int64')
landing_locations['teamName'] = landing_locations['name'].str.extract(r'([0-9A-Za-z]+)\_')
COLORS = {'ACTOZ': 'b', 'Rangers': 'r', 'GCBusan': 'c', 'ZDG': 'g'}
for player in positions.keys():
if 'ZDG' not in player and 'Rangers' not in player and \
'GCBusan' not in player and 'ACTOZ' not in player: continue
curpos = np.array(positions[player])
curpos[:, 2] = mapy - curpos[:, 2]
curlanding = landing_locations[landing_locations['name'] == player]
curpos = curpos[curpos[:, 0] > curlanding['time'].values[0]]
ax.plot(curpos[:, 1], curpos[:, 2], '--', c=COLORS[curlanding['teamName'].values[0]], linewidth=2, zorder=20)
# 경기 비행기라인 및 낙하산 거리 계산
current_match = pubg.match(matchId_rangers[2])
telemetry = current_match.get_telemetry()
positions = telemetry.player_positions()
circles = telemetry.circle_positions()
whites = np.array(circles['white'])
whites[:, 2] = mapy - whites[:, 2]
curpos = np.array(positions['Rangers_suk'])
curpos[:, 2] = mapy - curpos[:, 2]
unequips = telemetry.filter_by('log_item_unequip') # 아이템 제거한 이벤트
landing_locations = {unequip['character']['name']:
(unequip['character']['location']['x'], mapy - unequip['character']['location']['y'],
unequip['character']['team_id'])
for unequip in unequips if unequip['item']['item_id'] == 'Item_Back_B_01_StartParachutePack_C'} # 낙하산 제거
landing_locations = pd.DataFrame(landing_locations).T.reset_index()
landing_locations.columns = ['name', 'x', 'y', 'teamId']
landing_locations['teamId'] = landing_locations['teamId'].astype('int64')
map_id = telemetry.map_id()
mapx, mapy = map_dimensions[map_id]
#비행기 라인 기울기 및 절편 계산 (수송선 내에 있는 경우의 플레이어 데이터 이용)
slope1 = (curpos[0][2] - curpos[1][2]) / (curpos[0][1] - curpos[1][1])
beta1 = curpos[1][2] - curpos[1][1]*slope1
x = np.linspace(0, mapx, 100)
y = slope1*x + beta1
x = np.delete(x, np.where(y > mapy))
y = np.delete(y, np.where(y > mapy))
np.random.shuffle(COLORS)
map_range = (0, mapy)
map_range = np.array(map_range).astype('float64').reshape(-1, 1)
scaler = MinMaxScaler(feature_range=(0, 8))
scaler.fit(map_range)
# 낙하산 거리 계산 (선과 직선 사이의 수직선 거리 계산 공식 이용)
landing_locations['chuteDist'] = np.abs(slope1*landing_locations.x - landing_locations.y + beta1) / np.sqrt(slope1*slope1 + 1)
landing_locations['chuteDist'] = scaler.transform(landing_locations['chuteDist'].values.reshape(-1, 1))
landing_locations['teamName'] = landing_locations['name'].str.extract(r'([0-9A-Za-z]+)\_')
team_dists = landing_locations.groupby('teamName').mean()
team_dists['chuteDist'] = np.round(team_dists['chuteDist'], 2)
fig = plt.figure(figsize=(10, 10), dpi=100)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis("off")
img_path = '/home/idea_demo/LPoint/KYH/BattleGround/Maps/Erangel_Main_High_Res.jpg'
img = mpimg.imread(img_path)
ax.imshow(img, extent=[0, mapx, 0, mapy])
# 화이트존 그리기
white_circle = plt.Circle((whites[1][1], whites[1][2]), whites[1][4], edgecolor="w", linewidth=2, fill=False, zorder=5)
ax.add_patch(white_circle)
ax.plot(x, y, 'r--', linewidth=3, zorder=20) # 비행기 라인
used_teamId = []
for index, row in landing_locations.iterrows():
# 직교하는 선 구하기
slope2 = -1 / slope1
beta2 = row.y - row.x*slope2
x2 = -(beta1-beta2)/(slope1-slope2)
y2 = x2*slope1 + beta1
if not row['teamId'] in used_teamId: # 각 팀의 첫 번째만 글자 그리기
teamName = row["name"][:row['name'].find('_')]
label = ax.text(team_dists['x'][teamName], team_dists['y'][teamName] + np.random.randint(-10000, 10000),
'{}: {}Km'.format(teamName, team_dists['chuteDist'][teamName]),
color=COLORS[row['teamId']], size=10, zorder=22)
label.set_path_effects([patheffects.withStroke(linewidth=1.5, foreground='k')])
used_teamId.append(row['teamId'])
ax.plot([x2, row.x], [y2, row.y], c=COLORS[row['teamId']], linestyle='--', linewidth=0.5, zorder=15) # 선수와 비행기 간의 선
ax.scatter(row.x, row.y, marker="o", c=COLORS[row['teamId']], edgecolor="k", s=60, linewidths=1, zorder=20); # 선수
# 시즌 전체의 낙하산 거리 계산
fig = plt.figure(figsize=(10, 10), dpi=100)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis("off")
img = mpimg.imread(img_path)
ax.imshow(img, extent=[0, mapx, 0, mapy])
chute_dists = []
total_dists = pd.DataFrame()
whiteBetween_dists = pd.DataFrame()
for matchId in matchId_rangers:
current_match = pubg.match(matchId)
telemetry = current_match.get_telemetry()
positions = telemetry.player_positions()
curpos = np.array(positions[list(positions)[0]])
curpos[:, 2] = mapy - curpos[:, 2]
unequips = telemetry.filter_by('log_item_unequip')
landing_locations = {unequip['character']['name']:
(unequip['character']['location']['x'], mapy - unequip['character']['location']['y'],
unequip['character']['team_id'])
for unequip in unequips if (unequip['item']['item_id'] == 'Item_Back_B_01_StartParachutePack_C')}
landing_locations = pd.DataFrame(landing_locations).T.reset_index()
landing_locations.columns = ['name', 'x', 'y', 'teamId']
landing_locations['teamId'] = landing_locations['teamId'].astype('int64')
slope1 = (curpos[0][2] - curpos[1][2]) / (curpos[0][1] - curpos[1][1])
beta1 = curpos[1][2] - curpos[1][1]*slope1
landing_locations['chuteDist'] = np.abs(slope1*landing_locations.x - landing_locations.y + beta1) / np.sqrt(slope1*slope1 + 1)
landing_locations['chuteDist'] = scaler.transform(landing_locations['chuteDist'].values.reshape(-1, 1))
landing_locations['teamName'] = landing_locations['name'].str.extract(r'([0-9A-Za-z]+)\_')
team_dists = landing_locations.groupby('teamName').mean()
team_dists['chuteDist'] = np.round(team_dists['chuteDist'], 2)
total_dists = pd.concat([total_dists, team_dists], axis=0, sort=False)
rangers = landing_locations[landing_locations['teamName'] == 'Rangers']
hunters = landing_locations[landing_locations['teamName'] == 'Hunters']
actoz = landing_locations[landing_locations['teamName'] == 'ZDG']
entusf = landing_locations[landing_locations['teamName'] == 'EntusF']
ax.scatter(rangers.x, rangers.y, marker="o", c='r', edgecolor="k", s=60, linewidths=1, zorder=21); # 시즌 전체의 착륙 위치
ax.scatter(hunters.x, hunters.y, marker="o", c='c', edgecolor="k", s=60, linewidths=1, zorder=20);
ax.scatter(actoz.x, actoz.y, marker="o", c='g', edgecolor="k", s=60, linewidths=1, zorder=19);
ax.scatter(entusf.x, entusf.y, marker="o", c='b', edgecolor="k", s=60, linewidths=1, zorder=18);
total_dists['teamName'] = total_dists.index
total_dists = total_dists.reset_index(drop=True)
total_dists[['teamName', 'chuteDist']].groupby('teamName').mean()
chuteDist | |
---|---|
teamName | |
247 | 1.177778 |
ACTOZ | 0.992791 |
AFA | 1.127353 |
AFF | 1.003548 |
AGON | 0.818462 |
APK | 1.090556 |
BPT | 1.020000 |
BSG | 1.076667 |
C9 | 0.978889 |
DPG | 1.131667 |
DPGA | 1.073333 |
DTN | 1.208333 |
EM | 1.126667 |
EntusA | 0.966667 |
EntusF | 0.534000 |
GCBusan | 1.011613 |
GEN | 0.939091 |
Hunters | 1.118636 |
KDG | 1.152222 |
KDR | 0.693125 |
MVP | 0.955333 |
MVPL | 1.200625 |
Maxtill | 1.124516 |
NW | 0.687778 |
Quadro | 0.925200 |
ROGS | 1.010417 |
ROX | 0.890000 |
Rangers | 0.930000 |
RoccatA | 0.997600 |
RoccatI | 0.919583 |
SKT | 1.188000 |
WEGIRLS | 0.817500 |
WeGirls | 1.140000 |
ZDG | 0.885000 |
danawa | 1.028333 |
# chicken_dinner 데이터의 애니메이션 그리는 함수 코드
# mp4 파일 저장과 설정을 위해 일부 수정하였음
"""Function for generating playback animations."""
import logging
import os
import random
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from matplotlib import patheffects
from matplotlib import rc
from matplotlib.animation import FuncAnimation
from chicken_dinner.constants import COLORS
from chicken_dinner.constants import map_dimensions
rc("animation", embed_limit=100)
MAP_ASSET_PATH = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.realpath('./KYH/BattleGround')
)
),
"Maps"
)
def create_playback_animation(
telemetry,
filename="playback.html",
labels=True,
disable_labels_after=None,
label_players=None,
dead_players=True,
dead_player_labels=False,
zoom=False,
zoom_edge_buffer=0.5,
use_hi_res=False,
use_no_text=False,
color_teams=True,
highlight_teams=None,
highlight_players=None,
highlight_color="#FFFF00",
highlight_winner=False,
label_highlights=True,
care_packages=True,
damage=True,
end_frames=20,
size=10,
dpi=200,
interpolate=True,
interval=1,
fps=30,
):
"""Create a playback animation from telemetry data.
Using matplotlib's animation library, create an HTML5 animation saved to
disk relying on external ``ffmpeg`` library to create the video.
To view the animation, open the resulting file in your browser.
:param telemetry: an Telemetry instance
:param filename: a file to generate for the animation (default
"playback.html")
:param bool labels: whether to label players by name
:param int disable_labels_after: if passed, turns off player labels
after number of seconds elapsed in game
:param list label_players: a list of strings of player names that
should be labeled
:param bool dead_players: whether to mark dead players
:param list dead_player_labels: a list of strings of players that
should be labeled when dead
:param bool zoom: whether to zoom with the circles through the playback
:param float zoom_edge_buffer: how much to buffer the blue circle edge
when zooming
:param bool use_hi_res: whether to use the hi-res image, best to be set
to True when using zoom
:param bool use_no_text: whether to use the image with no text for
town/location names
:param bool color_teams: whether to color code different teams
:param list highlight_teams: a list of strings of player names whose
teams should be highlighted
:param list highlight_players: a list of strings of player names who
should be highlighted
:param str highlight_color: a color to use for highlights
:param bool highlight_winner: whether to highlight the winner(s)
:param bool label_highlights: whether to label the highlights
:param bool care_packages: whether to show care packages
:param bool damage: whether to show PvP damage
:param int end_frames: the number of extra end frames after game has
been completed
:param int size: the size of the resulting animation frame
:param int dpi: the dpi to use when processing the animation
:param bool interpolate: use linear interpolation to get frames with
second-interval granularity
:param int interval: interval between gameplay frames in seconds
:param int fps: the frames per second for the animation
"""
# Extract data
positions = telemetry.player_positions()
circles = telemetry.circle_positions()
rankings = telemetry.rankings()
winner = telemetry.winner()
killed = telemetry.killed()
rosters = telemetry.rosters()
damages = telemetry.player_damages()
package_spawns = telemetry.care_package_positions(land=False)
package_lands = telemetry.care_package_positions(land=True)
map_id = telemetry.map_id()
mapx, mapy = map_dimensions[map_id]
all_times = []
for player, pos in positions.items():
for p in p
애니메이션은 제외하고 올렸습니다.
'스터디 > 데이터 분석' 카테고리의 다른 글
[Kaggle] 타이타닉 생존자 예측 (0) | 2019.08.03 |
---|---|
[Kaggle] 뉴욕 택시여행 기간 예측 (0) | 2019.08.03 |
[게임데이터 분석] League Of Legends(롤) 바텀 듀오 티어 계산 (0) | 2019.08.03 |