05-03 07:38
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Data Science / Baseball] Retrosheet의 Game Log 데이터로부터 MLB 역대 관중수 알아보기 본문

Data Science/ Baseball Data Analysis

[Data Science / Baseball] Retrosheet의 Game Log 데이터로부터 MLB 역대 관중수 알아보기

cinema4dr12 2017. 4. 5. 21:43

앞선 포스팅(온라인 야구 데이터를 MongoDB에 저장하기)에서 Retrosheet의 Game Log 데이터를 불러오고 이를 MongoDB에 저장하는 방법에 대하여 알아보았다.

이번 포스팅에서는 저장된 Game Log 데이터로부터 메이저리그의 역대 관중수가 어떻게 변화되어 왔는지 알아보기로 한다.


1. MongoDB 서버 실행

이 포스팅은 Retrosheet의 Game Log 데이터가 MongoDB에 저장되어 있음을 가정하므로, 저장된 데이터를 가져오려면 MongoDB 서버가 실행되고 있다는 것 또한 가정한다.

만약 MongoDB 서버 실행 방법을 모른다면 이 링크를 참고하기 바란다.


2. 관중수 계산하기

Plotting을 위한 라이브러리 및 DB 관련 소스 로드하기

년도와 각 연도별 관중수를 Plotting하기 위해 plotly 패키지 라이브러리를 로드하고, 플롯된 이미지를 디스크에 저장하기 위해 webshot 패키지 라이브러리를 로드한다:


R CODE:

if (! ("plotly" %in% rownames(installed.packages()))) { install.packages("plotly") } base::require(plotly) if (! ("webshot" %in% rownames(installed.packages()))) { install.packages("webshot") webshot::install_phantomjs() } base::require(webshot) base::source('./ImportCollection.R', echo=FALSE)


MongoDB에 저장된 Game Log 데이터를 로딩하기 위해, 미리 작성한 R 소스파일을 로딩한다:


ImportCollection.R:

############################################################################## # ImportCollection.R ############################################################################## # @Author: Geol Choi, ph.D / cinema4dr12@gmail.com # @Date: Mar.4,2017 # @Description: To import document collection from MongoDB ############################################################################## source('./Connect.R', echo=FALSE) ## Import data by collection name ImportCollection <- function(colName) { con <- Connect(colName); df <- con$find(query = '{}'); rm(con); return(df); }


ImportCollection.R은 또한 Connect.R 소스파일을 참조한다:


CODE:

############################################################################## # Connect.R ############################################################################## # @Author: Geol Choi, ph.D / cinema4dr12@gmail.com # @Date: Mar.4,2017 # @Description: To insert Lahman data into MongoDB ############################################################################## ## intall packages & load them if (! ("mongolite" %in% rownames(installed.packages()))) { install.packages("mongolite") } base::library(mongolite) ################################################################################################ ## MongoDB connection Connect <- function(colName) { con <- mongolite::mongo(collection = colName, db = "baseball", url = "mongodb://localhost", verbose = TRUE, options = ssl_options()) return(con) } ################################################################################################ ## MongoDB insert InsertDB <- function(colName, basePath) { con <- Connect(colName); ## drop DB if any if(con$count() > 0) con$drop(); ## load data fileName <- base::sprintf("%s/%s.csv", basePath, colName); df <- utils::read.csv(fileName); ## insert document as data frame con$insert(df); ## disconnect base::rm(con); } ################################################################################################ ## MongoDB insert InsertDataFileToDB <- function(colName, fileName) { con <- Connect(colName); ## drop DB if any if(con$count() > 0) con$drop(); ## load data df <- utils::read.csv(fileName); ## insert document as data frame con$insert(df); ## disconnect base::rm(con); } ################################################################################################ ## MongoDB insert InsertDataFrameToDB <- function(colName, df) { con <- Connect(colName); ## drop DB if any if(con$count() > 0) con$drop(); ## insert document as data frame con$insert(df); ## disconnect base::rm(con); }


위의 R 파일을 다운로드 할 수 있다: 

ImportCollection.R

Connect.R

년도와 해당년도의 관중수를 기록한 DataFrame 정의

년도(year)와 해당년도의 관중수(attendances)를 기록하기 위해 DataFrame인 att를 하나 정의한다:

R CODE:

att <- base::data.frame(matrix(ncol = 2, nrow = 1)) base::names(att) <- base::c("year", "attendances")


attyearattendances라는 두 개의 피쳐(Features) - 두 개의 Columns - 를 갖는 DataFrame이다.

각 년도별 데이터 처리를 위한 for Loop

for Loop를 이용하여 Game Log가 기록된 1871년부터 2016년까지의 데이터를 처리할 수 있도록 한다:


R CODE:

rowIndex <- 0 for(year in 1871:2016) { ## @to do: get attendances for each year }


rowIndex는 해당 년도의 관중수 데이터가 유효할 경우 att에 새로운 행(Row)을 정의하여 해당 관중수를 기록하기 위함이다.

for Loop 내 데이터 처리

이제 for Loop 내에서 해당 년도의 Game Log 데이터를 MongoDB로부터 차례차례로 불러와 관중수 데이터를 얻어온다:


R CODE:

dataName <- base::sprintf("GameLog%d", year) GL <- ImportCollection(dataName)


첫번째 라인에서는, 해당년도의 Game Log 데이터인 "GameLog_####"의 이름을 정의한다. 예를 들어 2016년도의 경우 GameLog_2016이 된다.


두번째 라인에서는, ImportCollection.R에 정의되어 있는 ImportCollection() 함수를 통해 MongoDB로부터 해당 데이터를 불러와 변수 GL에 저장한다.

해당년도의 관중수 계산

관중수는 불러온 해당년도의 DataFrame 변수 GLX18에 저장되어 있다. 즉, GL$X18은 해당년도의 모든 경기의 관중수가 기록되어 있으므로 이를 모두 합하면 해당년도 전체의 관중수를 계산할 수 있다:


R CODE:

att_for_year <- base::sum(as.integer(GL$X18))


Retrosheet으로부터 1871년부터 2016년까지의 Game Log 데이터가 기록되어 있지만 1960년도 이전에는 관중수가 집계되지 않았으므로 관중수 데이터가 누락(NA)되어 있거나 0으로 기록되어 있다.

따라서, NA가 아니고(!is.na(att_for_year)) 기록된 관중수가 0보다 큰 경우(att_for_year > 0)에만 관중수를 att에 저장한다.

즉, 이 두 조건을 만족하는 경우에 한해서 행의 수를 하나 늘리고, 현재의 년도를 Console에 디스플레이하고, att에 합산된 해당년도의 관중수를 저장한다:


R CODE:

if(!is.na(att_for_year) && (att_for_year > 0)) { rowIndex <- rowIndex + 1 base::cat("\nYear:", year, ", Attendances: ", att_for_year, "\n") att[rowIndex,] <- base::c(year, att_for_year) }


3. plotly를 이용한 가시화 및 이미지 내보내기

마지막으로, plotly 패키지를 이용하여 년도별 관중수를 그래프로 가시화한다:


R CODE:

# plotting with Plotly p <- plotly::plot_ly(data = att, x = ~year, y = ~attendances, type = 'scatter', mode = 'lines+markers', line = list(color = 'rgb(205, 12, 24)',width = 3)) %>% layout(title = "Total attendances of the year", xaxis = list(title = "Year"), yaxis = list (title = "Total Attendances")) # print results print(p) # export the plotted image imgName <- base::sprintf("./attendances.png") plotly::export(p, file = imgName)



출력된 그래프를 살펴보면, 관중수가 대체적으로 증가해 왔으나 몇몇 년도에는 관중수가 대폭락 하였음을 알 수 있다.


우선, Console에 출력한 데이터를 확인해 보기로 했다.


Year: 1960 , Attendances:  19952080 
Year: 1961 , Attendances:  18906384 
Year: 1962 , Attendances:  21437721 
Year: 1963 , Attendances:  20738334 
Year: 1964 , Attendances:  21246757 
Year: 1965 , Attendances:  22536541 
Year: 1966 , Attendances:  25272850 
Year: 1967 , Attendances:  23944372 
Year: 1968 , Attendances:  22939361 
Year: 1969 , Attendances:  27308258 
Year: 1970 , Attendances:  28651549 
Year: 1971 , Attendances:  29197899 
Year: 1973 , Attendances:  30070026 
Year: 1977 , Attendances:  39205523 
Year: 1980 , Attendances:  43057819 
Year: 1981 , Attendances:  26557889 
Year: 1982 , Attendances:  44591457 
Year: 1983 , Attendances:  45329776 
Year: 1984 , Attendances:  44700744 
Year: 1985 , Attendances:  46791780 
Year: 1986 , Attendances:  47481734 
Year: 1987 , Attendances:  51976615 
Year: 1988 , Attendances:  52940478 
Year: 1989 , Attendances:  55373302 
Year: 1992 , Attendances:  55896281 
Year: 1993 , Attendances:  70212409 
Year: 1994 , Attendances:  49951608 
Year: 1995 , Attendances:  50479335 
Year: 1996 , Attendances:  60108260 
Year: 1997 , Attendances:  63179622 
Year: 1998 , Attendances:  70582891 
Year: 1999 , Attendances:  70306804 
Year: 2000 , Attendances:  72766556 
Year: 2001 , Attendances:  72552795 
Year: 2002 , Attendances:  67901899 
Year: 2003 , Attendances:  67607348 
Year: 2004 , Attendances:  72964347 
Year: 2005 , Attendances:  74862162 
Year: 2006 , Attendances:  75996673 
Year: 2007 , Attendances:  79458251 
Year: 2008 , Attendances:  78577735 
Year: 2009 , Attendances:  73375656 
Year: 2010 , Attendances:  73037492 
Year: 2011 , Attendances:  73383269 
Year: 2012 , Attendances:  74815041 
Year: 2013 , Attendances:  73985730 
Year: 2014 , Attendances:  73701356 
Year: 2016 , Attendances:  73119644 


첫번째로 눈의 띄는 것은 1974년에서 1976년까지 관중수 기록이 없다. 그래서 Wikipedia에서 MLB 파업 기록을 살펴보니, 파업년도는 다음과 같았다:


  • 1972 Major League Baseball strike

  • 1973 Major League Baseball lockout

  • 1976 Major League Baseball lockout

  • 1980 Major League Baseball strike

  • 1981 Major League Baseball strike

  • 1985 Major League Baseball strike

  • 1990 Major League Baseball lockout

  • 1994–95 Major League Baseball strike


1973, 1976, 1990년도에 있었던 lockout이라는 것은, 고용주가 특정한 조건에 동의할 때까지 근로자를 출근하지 못하게 하는 것이라고 한다. 어쨌든 파업(strike)과 로크 아웃(lockout)은 분명 관중수 동원에 영향을 미쳤을 것이다.


1980년도까지 꾸준히 증가했던 관중수는 1981년 파업에 의해 폭락했으나, 1985년도의 파업은 관중수 폭락에 영향을 미치지는 않는 것같고 오히려 전년보다 관중수가 소폭 증가하였다.


또다른 파업이 있었던 1990년도에는 관중수 기록이 없으며, 1993년도에는 무슨 일이 있었는지 관중수가 전년에 비해 엄청나게 폭등하였다 (미국 달력을 보고 조사해 보지는 않았지만 연휴가 많은 것이 원인일 수도 있을 것 같다 - 확인되지 않은 사항).


파업이 있었던 1994년과 1995년 역시 관중수가 전년도에 비해 대폭 감소하였다 (무려 30%나 감소하였다). 그 후, 다시 꾸준히 증가하여 2007년에 역대 최다 관중수(8천만명에 가까운)를 기록하였다.


5. 전체 소스 코드

GameLogExample.R



6. 본 포스팅을 마치며

이번 포스팅에서는 메이저리그의 역대 관중수를 Retrosheet Game Log 데이터를 통해 알아보았다.

역대 관중수 뿐만아니라 Game Log 데이터를 통해 최다 관중수를 보유한 팀을 알아본다든가 요일별 관중수를 알아본다든가 하는 다양한 기록을 도출해 볼 수 있다.

본 포스팅을 통해 학습한 내용을 응용하면 훨씬 더 재밌고 흥미로운 데이터 도출을 통찰을 얻을 수 있으며, 이것이 데이터 마이닝이다.

Comments