일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Big Data
- openCV
- 우리들교회
- 빅 데이터
- 김양재 목사
- WebGL
- 인공지능
- Deep learning
- 딥러닝
- data science
- node.js
- nodeJS
- c++
- 빅데이타
- 김양재
- 빅데이터
- 김양재 목사님
- Artificial Intelligence
- R
- 확률
- No SQL
- 빅 데이타
- 주일설교
- probability
- Statistics
- 데이터 과학
- 통계
- MongoDB
- 몽고디비
- Machine Learning
- Today
- Total
Scientific Computing & Data Science
[Data Science / Baseball] Lahman 데이터를 이용한 야구 데이터 분석 Part 4. 본문
[Data Science / Baseball] Lahman 데이터를 이용한 야구 데이터 분석 Part 4.
cinema4dr12 2017. 5. 18. 21:45Lahman 데이터를 이용한 야구 데이터 분석 Part 4.
QUESTIONS
Q1. 1980년부터 2016년까지 MLB의 요일별 누적 관중수는 어떻게 될까?
지난 포스팅에 이어 이번 포스팅에서는 1980년부터 2016년까지의 메이저리그 요일별 누적 관중수를 계산하여 그래프로 출력해 보도록 하겠다. 데이터는 Retrosheet의 Game Log 데이터로부터 계산되며, 이 데이터를 MongoDB로 입출력하는 방법에 대하여서는 "온라인 야구 데이터를 MongoDB에 저장하기"를 참고하기 바란다.
패키지 및 소스 로딩하기
그래프 출력 및 그래프 저장을 위해 plotly와 webshot 패키지를 로딩한다:
1 2 3 4 5 6 7 8 | 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) | cs |
또한, MongoDB로부터 Retrosheet의 Game Log 데이터 로딩을 위해 R 소스를 로딩한다:
1 | base::source('./ImportCollection.R', echo=FALSE) | cs |
참고로 ImportCollection.R 파일은 다음과 같다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ############################################################################## # 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); } | cs |
또한, ImportCollection.R은 Connect.R 소스를 로딩하며, 이 소스는 다음과 같다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | ############################################################################## # 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); } | cs |
요일 별 관중수 계산
요일 별 관중수를 계산할 대상년도는 1980년부터 2016년까지로 하였다.
1 | years <- 1980:2016 | cs |
요일 별 관중수를 저장할 Data Frame 변수 att_weekday(Attendance each weekday)를 정의하여 다음과 같이 초기화하였다:
1 2 3 | att_weekday <- base::as.data.frame(base::matrix(0, nrow=7, ncol=2)) base::names(att_weekday) <- base::c("Weekday", "Attendance") att_weekday[,1] <- base::c("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN") | cs |
이제 1980년부터 2016년까지 MongoDB로부터 각 년도에 대한 Game Log 데이터를 불러와 처리를 한다:
1 2 3 | for(year in years) { # 해당 년도에 대한 데이터 처리... } | cs |
이제부터의 내용은 상기 for loop에서 처리하는 코드이다.
MongoDB로부터 해당년도에 대한 Game Log 데이터를 불러온다:
1 2 3 | tmp <- base::sprintf("GameLog%4d", year) GL_YEAR <- ImportCollection(tmp) utils::head(GL_YEAR) | cs |
R의 subset() 함수를 이용하여 요일별로 데이터를 분리하는데, Game Log 데이터의 X3는 해당 게임이 치뤄진 요일이 기록되어 있는 Field이다 (참고로 Field에 대한 정보는 Retrosheet Game Log Guide를 참고하면 된다):
1 2 3 4 5 6 7 | GL_MON <- base::subset(x=GL_YEAR, X3=="Mon") GL_TUE <- base::subset(x=GL_YEAR, X3=="Tue") GL_WED <- base::subset(x=GL_YEAR, X3=="Wed") GL_THU <- base::subset(x=GL_YEAR, X3=="Thu") GL_FRI <- base::subset(x=GL_YEAR, X3=="Fri") GL_SAT <- base::subset(x=GL_YEAR, X3=="Sat") GL_SUN <- base::subset(x=GL_YEAR, X3=="Sun") | cs |
게임의 관중수는 Game Log 데이터의 X18 필드에 해당하므로 이 필드 값들을 합산하면 해당년도의 각 요일별 관중수를 계산할 수 있다:
1 2 3 4 5 6 7 | ATT_MON <- base::sum(GL_MON$X18) ATT_TUE <- base::sum(GL_TUE$X18) ATT_WED <- base::sum(GL_WED$X18) ATT_THU <- base::sum(GL_THU$X18) ATT_FRI <- base::sum(GL_FRI$X18) ATT_SAT <- base::sum(GL_SAT$X18) ATT_SUN <- base::sum(GL_SUN$X18) | cs |
앞서 정의한 바와 같이, att_weekday 변수의 행은 모두 7개이며 1, 2, 3, 4, 5, 6, 7은 각각 월, 화, 수, 목, 금, 토, 일요일을 의미하며, 첫번째 열은 요일을, 두번째 열은 관중수를 의미한다. 가령,
> utils::head(att_weekday)
Weekday Attendance
1 MON 0
2 TUE 0
3 WED 0
4 THU 0
5 FRI 0
6 SAT 0
과 같다.
이제 각 해당년도에 대한 요일별 관중수를 att_weekday에 누적하되, 유효한 값이 아닐 경우 무시한다:
1 2 3 4 5 6 7 | if(!is.na(ATT_MON)) att_weekday[1,2] <- att_weekday[1,2] + ATT_MON if(!is.na(ATT_TUE)) att_weekday[2,2] <- att_weekday[2,2] + ATT_TUE if(!is.na(ATT_WED)) att_weekday[3,2] <- att_weekday[3,2] + ATT_WED if(!is.na(ATT_THU)) att_weekday[4,2] <- att_weekday[4,2] + ATT_THU if(!is.na(ATT_FRI)) att_weekday[5,2] <- att_weekday[5,2] + ATT_FRI if(!is.na(ATT_SAT)) att_weekday[6,2] <- att_weekday[6,2] + ATT_SAT if(!is.na(ATT_SUN)) att_weekday[7,2] <- att_weekday[7,2] + ATT_SUN | cs |
그래프로 출력하기
plotly 패키지를 이용하여 att_weekday에 저장된 요일별 관중수를 출력하도록 한다:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # plotting with Plotly p <- plotly::plot_ly(data = att_weekday, x = ~Weekday, y = ~Attendance, type = 'scatter', mode = 'lines+markers') %>% layout(title = "Total attendance per weekday from 1980 to 2016", xaxis = base::list( title = "Day of Week", type = "category", categoryorder = "trace", showgrid = TRUE, showline = TRUE, autorange = TRUE, showticklabels = TRUE, ticks = "outside", tickangle = 0 ), yaxis = base::list(title = "Attendance")) # print results base::print(p) | cs |
출력 결과는 다음과 같다:
예상했던 바와 같이 주말에 관중수가 가장 많으며, 월요일과 목요일에 관중수가 가정 적었음을 알 수 있다.
그러나, 단순히 요일별 누적 관중수보다 해당 요일에 치뤄진 경기수를 고려하여 계산하는 것이 더 의미있을 수 있다. 왜냐하면 아무래도 월요일에는 경기수가 가장 적기 때문이다. 따라서, 해당 요일의 경기 당 평균관중수를 계산해보는 것을 시도해 보기 바란다.
전체 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | ####################################################################### # @Author: Geol Choi, ph.D / cinema4dr12@gmail.com # @Date: May.18,2017 # @Description: MLB Data Analysis ####################################################################### base::rm(list = ls()) base::gc() 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) ####################################################################### ## Question 3: Attendances each weekday # How many extra people attend ballgames during the weekend? # What’s the average attendance by day of the week? ####################################################################### years <- 1980:2016 att_weekday <- base::as.data.frame(base::matrix(0, nrow=7, ncol=2)) base::names(att_weekday) <- base::c("Weekday", "Attendance") att_weekday[,1] <- base::c("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN") for(year in years) { tmp <- base::sprintf("GameLog%4d", year) GL_YEAR <- ImportCollection(tmp) utils::head(GL_YEAR) GL_MON <- base::subset(x=GL_YEAR, X3=="Mon") GL_TUE <- base::subset(x=GL_YEAR, X3=="Tue") GL_WED <- base::subset(x=GL_YEAR, X3=="Wed") GL_THU <- base::subset(x=GL_YEAR, X3=="Thu") GL_FRI <- base::subset(x=GL_YEAR, X3=="Fri") GL_SAT <- base::subset(x=GL_YEAR, X3=="Sat") GL_SUN <- base::subset(x=GL_YEAR, X3=="Sun") ATT_MON <- base::sum(GL_MON$X18) ATT_TUE <- base::sum(GL_TUE$X18) ATT_WED <- base::sum(GL_WED$X18) ATT_THU <- base::sum(GL_THU$X18) ATT_FRI <- base::sum(GL_FRI$X18) ATT_SAT <- base::sum(GL_SAT$X18) ATT_SUN <- base::sum(GL_SUN$X18) if(!is.na(ATT_MON)) att_weekday[1,2] <- att_weekday[1,2] + ATT_MON if(!is.na(ATT_TUE)) att_weekday[2,2] <- att_weekday[2,2] + ATT_TUE if(!is.na(ATT_WED)) att_weekday[3,2] <- att_weekday[3,2] + ATT_WED if(!is.na(ATT_THU)) att_weekday[4,2] <- att_weekday[4,2] + ATT_THU if(!is.na(ATT_FRI)) att_weekday[5,2] <- att_weekday[5,2] + ATT_FRI if(!is.na(ATT_SAT)) att_weekday[6,2] <- att_weekday[6,2] + ATT_SAT if(!is.na(ATT_SUN)) att_weekday[7,2] <- att_weekday[7,2] + ATT_SUN } # plotting with Plotly p <- plotly::plot_ly(data = att_weekday, x = ~Weekday, y = ~Attendance, type = 'scatter', mode = 'lines+markers') %>% layout(title = "Total attendance per weekday from 1980 to 2016", xaxis = base::list( title = "Day of Week", type = "category", categoryorder = "trace", showgrid = TRUE, showline = TRUE, autorange = TRUE, showticklabels = TRUE, ticks = "outside", tickangle = 0 ), yaxis = base::list(title = "Attendance")) # print results base::print(p) | cs |
'Data Science > Baseball Data Analysis' 카테고리의 다른 글
[Data Science / Baseball] rvest 패키지를 이용하여 KBO 야구 데이터 가져오기 (1) | 2017.05.14 |
---|---|
[Data Science / Baseball] rvest 패키지를 이용하여 웹페이지로부터 야구 데이터 가져오기 (0) | 2017.05.09 |
[Data Science / Baseball] Retrosheet의 Game Log 데이터로부터 MLB 역대 관중수 알아보기 (1) | 2017.04.05 |
[Data Science / Baseball] 온라인 야구 데이터를 MongoDB에 저장하기 (0) | 2017.03.23 |
[Data Science / Baseball] Lahman 데이터를 이용한 야구 데이터 분석 Part 3. (0) | 2017.03.09 |