데이터 분석

R을 이용한 축구 데이터 분석 (MAP)

r-code-for-data-analysis 2023. 6. 11. 17:38

오늘 새벽 유럽 챔피언스 결승 경기로 많은 사람들이 아침잠을 설쳤을 것이다. 
R을 이용하여 축구 데이터 분석을 할 수 있는 블로그를 발견하여 약간 변형하여 따라 해 보았다. 
 

 
참조 블로그
https://towardsdatascience.com/how-to-visualize-football-data-using-r-ee963b3a0ba4

 

How to Visualize Football Data Using R

Tutorials on creating shots, passes, and heat maps

towardsdatascience.com

 
위 예시는 옛날 경기라 20/21 라리가의 메시를 중심으로 데이터 분석을 다시 진행하였다. 
 
필요한 패키지 설치 및 라이브러리 불러오기

# 필요한 라이브러리 설치
install.packages('devtools') 
devtools::install_github("statsbomb/SDMTools") 
devtools::install_github("statsbomb/StatsBombR") 
install.packages('tidyverse') 
install.packages('ggsoccer' )

# 라이브러리 로드
library(tidyverse) 
library(StatsBombR) 
library(ggsoccer)

 
축구 오픈 데이터 깃허브 주소는 아래와 같다. 
https://github.com/statsbomb/open-data

 

GitHub - statsbomb/open-data: Free football data from StatsBomb

Free football data from StatsBomb. Contribute to statsbomb/open-data development by creating an account on GitHub.

github.com

 
데이터 불러오기 (20/21년 스페인 라리가 바르셀로나와 셀타 비고 경기)

# 사용 가능한 모든 대회 검색
Comp <- FreeCompetitions()


# 대회 필터링
ucl_german <- Comp %>% 
  filter(competition_id==11 & season_name=="2020/2021")

# Retrieve all available matches
matches <- FreeMatches(ucl_german)

# Retrieve the event data
events_df <- get.matchFree(matches)

# 데이터 전처리
clean_df <- allclean(events_df)

메시의 패스 데이터 불러와서 시각화 하기

# 패스 맵
messi_pass <- clean_df %>% 
  filter(player.name == 'Lionel Andrés Messi Cuccittini') %>% 
  filter(type.name == 'Pass')


ggplot(messi_pass) + 
  annotate_pitch(dimensions = pitch_statsbomb) + 
  geom_segment(aes(x=location.x, y=location.y, xend=pass.end_location.x, yend=pass.end_location.y), 
               colour = "coral",
               arrow = arrow(length = unit(0.15, "cm"), 
                             type = "closed")) + 
  labs(title="Lionel Andrés Messi's Passing Map", 
       subtitle="La Liga 20/21", 
       caption=" 데이터 소스: StatsBomb")+ 
  theme(
    plot.background = element_rect(fill='#021e3f', color='#021e3f'),
    panel.background = element_rect(fill='#021e3f', color='#021e3f'),
    plot.title = element_text(hjust=0.5, vjust=0, size=14),
    plot.subtitle = element_text(hjust=0.5, vjust=0, size=8),
    plot.caption = element_text(hjust=0.5),
    text = element_text(family="Geneva", color='white'),
    panel.grid = element_blank(),
    axis.title = element_blank(),
    axis.text = element_blank()
  )

각 팀의 슛 맵을 그려보자

barcelona_shot <- clean_df %>% 
  filter(type.name == 'Shot') %>% 
  filter(team.name == 'Barcelona') %>% 
  select(player.name, location.x, location.y, shot.end_location.x, shot.end_location.y, shot.statsbomb_xg)
celta_shot <- clean_df %>% 
  filter(type.name == 'Shot') %>% 
  filter(team.name == 'Celta Vigo') %>% 
  select(player.name, location.x, location.y, shot.end_location.x, shot.end_location.y, shot.statsbomb_xg)


ggplot() + 
  annotate_pitch(dimensions = pitch_statsbomb, colour='white', fill='#021e3f') + 
  geom_point(data=barcelona_shot, aes(x=location.x, y=location.y, size=shot.statsbomb_xg) , color="red") + 
  geom_point(data=celta_shot, aes(x=120-location.x, y=location.y, size=shot.statsbomb_xg), color="yellow") +
  labs( title= "Barcelona vs Celta Vigo", 
        subtitle = "Shots Map | La Liga 20/21",
        caption="Data Source: StatsBomb"  ) + 
  theme(
    plot.background = element_rect(fill='#021e3f', color='#021e3f'),
    panel.background = element_rect(fill='#021e3f', color='#021e3f'),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.x = element_blank(),
    axis.text.y = element_blank(),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    text = element_text(family="Geneva", color='white'),
    plot.title = element_text(hjust=0.5, vjust=0, size=14),
    plot.subtitle = element_text(hjust=0.5, vjust=0, size=8),
    plot.caption = element_text(hjust=0.5),
    plot.margin = margin(2, 2, 2, 2),
    legend.position = "none"
  )

 

 
바르셀로나가 셀타비고를 압박하는 pressure map 그려보기

# Pressure Heat Map
barcelona_pressure <- clean_df %>%
  filter(team.name == 'Barcelona') %>%
  filter(type.name == 'Pressure')



ggplot(barcelona_pressure)+
  annotate_pitch(dimensions = pitch_statsbomb, fill='#021e3f', colour='#DDDDDD') +
  geom_density2d_filled(aes(location.x, location.y, fill=..level..), alpha=0.4, contour_var='ndensity') +
  scale_x_continuous(c(0, 120)) +
  scale_y_continuous(c(0, 80)) +
  labs(title="Barcelona's Pressure Heat Map",
       subtitle="La Liga 20/21", 
       caption=" 데이터 소스: StatsBomb")+ 
  theme_minimal() +
  theme(
    plot.background = element_rect(fill='#021e3f', color='#021e3f'),
    panel.background = element_rect(fill='#021e3f', color='#021e3f'),
    plot.title = element_text(hjust=0.5, vjust=0, size=14),
    plot.subtitle = element_text(hjust=0.5, vjust=0, size=8),
    plot.caption = element_text(hjust=0.5),
    text = element_text(family="Geneva", color='white'),
    panel.grid = element_blank(),
    axis.title = element_blank(),
    axis.text = element_blank(),
    legend.position = "none"
  )

 
앞으로 스포츠 데이터 분석 분야는 더 많은 수요가 있지 않을까?

 

728x90
반응형