12-23 00:00
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Data Science / Baseball] 온라인 야구 데이터를 MongoDB에 저장하기 본문

Data Science/ Baseball Data Analysis

[Data Science / Baseball] 온라인 야구 데이터를 MongoDB에 저장하기

cinema4dr12 2017. 3. 23. 23:01

Retrosheet는 메이저리그 야구의 play-by-play Game Logs를 .zip 압축 파일 형태로 제공한다.


Game Logs를 분석하기 위해 Retrosheet 웹사이트에서 일일이 .zip 파일들을 다운받아 압축을 풀어 불러올 수 있겠지만 여간 번거로운 것이 아닐 것이다.


이번 포스팅에서는 Retrosheet 웹사이트가 제공하는 Game Logs 파일들을 다운받아 CSV 형식으로 Data Frame에 저장하고 이를 MongoDB에 저장하고 또한 DB로부터 데이터를 불러오는 방법에 대하여 설명하도록 하겠다.


우선 Retrosheet 웹사이트를 방문하면 상단에 Data downloads > Game logs를 클릭한다.





Game logs 페이지에 보면 1871년부터 2016년까지의 Game Logs 파일에 대한 링크들을 볼 수 있을 것이다.

이 중 하나를 클릭해 보자. 가령, 2016년도 Game Log를 클릭하면, gl2016.zip 파일이 다운로드 될 것이다.


이들 각각의 파일 링크 주소는 다음과 같은 형식이다:


http://www.retrosheet.org/gamelogs/gl{YEAR}.zip


결국 이 경로에 연도만 바꿔주면 이들 모두를 일괄 처리할 수 있는 것이다.


이제 MongoDB를 실행한다:


$ mongod --dbpath {YOUR_MONGODB_DATA_PATH}


이제 R에서 mongolite 라이브러리 패키지를 불러오고,


R CODE:

## intall packages & load them if (! ("mongolite" %in% rownames(installed.packages()))) { install.packages("mongolite") } base::library(mongolite)


MongoDB의 Document Collection을 입력받아 connection을 수립하는 함수를 작성한다:


R CODE:

################################################################################################ ## MongoDB connection Connect <- function(colName) { con <- mongolite::mongo(collection = colName, db = "baseball", url = "mongodb://localhost", verbose = TRUE, options = ssl_options()) return(con) }


Document Collection 이름과 Data Frame을 입력받아 이 Data Frame을 MongoDB의 해당 Document Collection에 저장하는 함수를 작성한다:


R CODE:

################################################################################################ ## 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); }


이제 다운받을 Game Logs 연도 시퀀스를 정의한다 (1871~2016년까지로 정하였다):


R CODE:

seq_range <- base::seq(from = 1871, to = 2016, by = 1)


Retrosheet의 Game Logs의 .zip 파일들을 임시로 저장할 임시 경로를 생성한다:


R CODE:

temp <- base::tempfile()


R의 빌트-인(Built-in) 함수인 utils::download.file()를 각 경로의 파일들을 임시 경로에 다운받는다:


R CODE:

filePath <- base::sprintf("http://www.retrosheet.org/gamelogs/gl%d.zip", year) utils::download.file(filePath, temp)


year는 seq_range로부터 차례로 불러오는 1871년부터 2016년까지의 연도이다.


Document Collection의 이름과 파일이름을 해당년도에 따라 순차적으로 정한다:


R CODE:

collectionName <- base::sprintf("GameLog%04d", year) fileName <- base::sprintf("GL%04d.TXT", year)


R의 base::unz() 함수를 이용하여 해당 .zip 파일의 압축을 풀고, 이를 read.csv() 파일을 이용하여 Data Frame 형식으로 저장한다:


R CODE:

data <- utils::read.csv(base::unz(temp, fileName))


한 가지 고려해야 할 사항은, 변수 data가 Data Frame임에도 열 이름(Column Names)가 정해져 있지 않다는 것이다. 열 이름이 정해져 있지 않으면 데이터 처리에 오류를 가져올 수 있으므로 열의 개수(곧, Features 수) 만큼 X1, X2, X3, ... 형식으로 적당한 이름을 붙인다 - 구체적인 이름을 붙이기에는 열의 개수가 매우 많다.


R CODE:

for(i in 1:base::ncol(df)) { names(df)[i] <- base::sprintf("X%d", i) }



이를 앞서 정의한 InsertDataFrameToDB() 함수를 이용하여 MongoDB에 저장한다:


R CODE:

InsertDataFrameToDB(colName = collectionName, df = data)


Loop가 모두 완료되면, 파일을 다운로드하기 위해 임시로 생성한 경로의 링크를 해제한다:


R CODE:

base::unlink(temp)


지금까지 언급한 일련의 과정에 대한 전체 R Code는 다음과 같다:


R Code:



코드를 실행하여 1871년부터 2016년까지 MongoDB에 저장하는데 걸린 시간은 5분 정도였다.




Robomongo를 이용하여 데이터가 잘 들어왔는지 확인해 보자:




데이터가 모두 잘 들어왔음을 알 수 있다.


마지막으로 DB에 저장된 데이터를 Data Frame으로 불러오는 코드를 작성해 본다:


R CODE:

## 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) } ################################################################################################ ## Import document collection from MongoDB ImportCollection <- function(colName) { con <- Connect(colName); df <- con$find(query = '{}'); rm(con); return(df); } df <- ImportCollection("GameLog2016")


df에 이를 데이터가 잘 불러와졌는지 확인한다:


> head(df)
  X20160403 X0 Sun NYN NL X1 KCA AL X1_1 X3 X4 X51 N X X_2 KAN06 X40030 X193 X000000030 X10010200x X33 X7 X1_2 X0_1
1  20160403  0 Sun TOR AL  1 TBA AL    1  5  3  54 D       STP01  31042  171  200100020  001000002  35  7    1    0
2  20160403  0 Sun SLN NL  1 PIT NL    1  1  4  51 D       PIT08  39500  182  000000001  02000101x  32  5    0    0
3  20160404  0 Mon CHN NL  1 ANA AL    1  9  0  54 N       ANA01  44020  188  100202103  000000000  37 11    3    0
4  20160404  0 Mon MIN AL  1 BAL AL    1  2  3  53 D       BAL12  45785  168  000000200  000020001  33  7    3    0
5  20160404  0 Mon CHA AL  1 OAK AL    1  4  3  54 N       OAK01  35067  176  004000000  003000000  33  7    1    1
6  20160404  0 Mon TOR AL  2 TBA AL    2  5  3  54 N       STP01  15116  178  001310000  010011000  33  7    1    0
  X0_2 X3_1 X0_3 X0_4 X0_5 X6 X0_6 X9 X0_7 X1_3 X0_8 X0_9 X9_1 X3_2 X3_3 X3_4 X0_10 X0_11 X24 X15 X1_4 X1_5 X3_5
1    1    5    0    0    0  3    0 16    0    0    0    0    6    2    3    3     1     0  27  15    2    0    0
2    0    1    0    0    1  5    0 14    0    0    1    0   10    3    4    4     0     0  24  11    0    0    2
3    1    9    0    0    0  7    1 12    0    0    1    0    8    3    0    0     0     0  27   9    0    0    1
4    0    2    0    1    1  0    0 10    0    0    0    0    6    6    3    3     1     0  26   5    0    0    0
5    0    2    0    0    2  1    0  6    0    2    0    0    5    5    3    3     0     0  27   9    1    0    0
6    3    5    0    1    0  2    0  9    0    0    0    0    4    5    3    3     1     0  27   8    1    0    0
  X0_12 X30 X9_2 X0_13 X0_14 X0_15 X4_1 X0_16 X1_6 X0_17 X2 X0_18 X3_6 X1_7 X0_19 X3_7 X0_20 X5 X5_1 X3_8 X3_9
1     0  35    7     1     0     1    3     0    0     0  1     0    7    0     1    0     0  6    4    4    4
2     0  28    9     2     1     0    4     1    1     1  5     0    5    0     1    1     0  8    4    1    1
3     0  29    3     1     0     0    0     0    0     0  1     0    7    0     0    0     0  3    5    9    9
4     0  36   10     3     0     0    3     0    0     0  5     0   10    1     0    0     0 12    6    2    2
5     0  33    7     2     0     0    3     0    0     0  3     0   10    0     0    0     0  6    6    2    2
6     0  35    8     1     0     1    2     0    0     0  4     0    9    1     0    0     0  9    4    5    5
  X0_21 X0_22 X27 X13 X0_23 X0_24 X0_25 X0_26 davig901  Gerry_Davis holbs901       Sam_Holbrook drakr901
1     1     0  27   8     1     0     0     0 everm901 Mike Everitt emmep901         Paul Emmel timmt901
2     0     0  27   8     1     0     1     0 laynj901  Jerry Layne wendh902 Hunter Wendelstedt gibsh902
3     0     0  27   8     1     0     1     0 barrt901  Ted Barrett herna901    Angel Hernandez barkl901
4     0     0  27   6     0     0     0     0 wintm901 Mike Winters wegnm901        Mark Wegner fostm901
5     0     0  27  12     2     0     0     0 hallt901  Tom Hallion cuzzp901         Phil Cuzzi belld901
6     1     0  27   6     0     0     0     0 emmep901   Paul Emmel timmt901        Tim Timmons diazl901
        Rob_Drake torrc901   Carlos_Torres X_none_ X_none__1 collt801 Terry_Collins yoste001       Ned_Yost
1     Tim Timmons diazl901        Laz Diaz  (none)    (none) gibbj001  John Gibbons cashk001     Kevin Cash
2    Tripp Gibson fagac901     Clint Fagan  (none)    (none) mathm001  Mike Matheny hurdc001   Clint Hurdle
3 Lance Barksdale littw901     Will Little  (none)    (none) maddj801    Joe Maddon sciom001  Mike Scioscia
4    Marty Foster muchm901 Mike Muchlinski  (none)    (none) molip001  Paul Molitor showb801 Buck Showalter
5     Dan Bellino morag901    Gabe Morales  (none)    (none) ventr001 Robin Ventura melvb001     Bob Melvin
6        Laz Diaz everm901    Mike Everitt  (none)    (none) gibbj001  John Gibbons cashk001     Kevin Cash
  volqe001   Edinson_Volquez harvm001      Matt_Harvey daviw001      Wade_Davis hosme001       Eric_Hosmer
1 strom001    Marcus Stroman archc001     Chris Archer osunr001   Roberto Osuna encae001 Edwin Encarnacion
2 lirif001 Francisco Liriano waina001  Adam Wainwright                   (none) lirif001 Francisco Liriano
3 arrij001      Jake Arrieta richg002 Garrett Richards                   (none) rizza001     Anthony Rizzo
4 britz001      Zach Britton jepsk001     Kevin Jepsen                   (none) wietm001      Matt Wieters
5 salec001        Chris Sale hillr001        Rich Hill robed002 David Robertson eatoa002        Adam Eaton
6 dickr001       R.A. Dickey smyld001       Drew Smyly osunr001   Roberto Osuna tulot001   Troy Tulowitzki
  harvm001_1   Matt_Harvey_1 volqe001_1 Edinson_Volquez_1 granc001 Curtis_Granderson X9_3 wrigd002   David_Wright
1   strom001  Marcus Stroman   archc001      Chris Archer pillk001      Kevin Pillar    8 donaj001 Josh Donaldson
2   waina001 Adam Wainwright   lirif001 Francisco Liriano carpm002    Matt Carpenter    5 phamt001     Tommy Pham
3   arrij001    Jake Arrieta   richg002  Garrett Richards fowld001     Dexter Fowler    8 heywj001  Jason Heyward
4   sante001   Ervin Santana   tillc001     Chris Tillman dozib001      Brian Dozier    4 mauej001      Joe Mauer
5   salec001      Chris Sale   hillr001         Rich Hill eatoa002        Adam Eaton    9 rollj001  Jimmy Rollins
6   dickr001     R.A. Dickey   smyld001        Drew Smyly pillk001      Kevin Pillar    8 donaj001 Josh Donaldson
  X5_2 cespy001 Yoenis_Cespedes X7_1 dudal001        Lucas_Duda X3_10 walkn001      Neil_Walker X4_2 confm001
1    5 bautj002   Jose Bautista    9 encae001 Edwin Encarnacion    10 tulot001  Troy Tulowitzki    6 colac001
2    7 hollm001   Matt Holliday    3 gricr001    Randal Grichuk     8 piscs001 Stephen Piscotty    9 moliy001
3    9 zobrb001     Ben Zobrist    4 rizza001     Anthony Rizzo     3 bryak001      Kris Bryant    5 schwk001
4    3 sanom001     Miguel Sano    9 plout001    Trevor Plouffe     5 rosae001    Eddie Rosario    7 parkb002
5    6 abrej003      Jose Abreu    3 frazt001      Todd Frazier     5 cabrm002    Melky Cabrera    7 garca003
6    5 bautj002   Jose Bautista    9 encae001 Edwin Encarnacion    10 tulot001  Troy Tulowitzki    6 colac001
  Michael_Conforto X10 cabra002 Asdrubal_Cabrera X6_1 darnt001 Travis_d_Arnaud X2_1 lagaj001    Juan_Lagares X8
1  Chris Colabello   3 saunm001 Michael Saunders    7 martr004  Russell Martin    2 goinr001      Ryan Goins  4
2    Yadier Molina   2 wongk001      Kolten Wong    4 gyorj001     Jedd Gyorko    6 waina001 Adam Wainwright  1
3   Kyle Schwarber   7 solej001      Jorge Soler   10 montm001  Miguel Montero    2 russa002 Addison Russell  6
4    Byung Ho Park  10 escoe001  Eduardo Escobar    6 suzuk001     Kurt Suzuki    2 buxtb001    Byron Buxton  8
5   Avisail Garcia  10 lawrb002     Brett Lawrie    4 navad001  Dioner Navarro    2 jacka001  Austin Jackson  8
6  Chris Colabello   3 saunm001 Michael Saunders    7 goinr001      Ryan Goins    4 tholj001      Josh Thole  2
  escoa003 Alcides_Escobar X6_2 mousm001   Mike_Moustakas X5_3 cainl001  Lorenzo_Cain X8_1 hosme001_1
1 forsl001  Logan Forsythe    4 morrl001   Logan Morrison    3 longe001 Evan Longoria    5   dickc002
2 jasoj001       John Jaso    3 mccua001 Andrew McCutchen    8 freed001  David Freese    5   marts002
3 escoy001   Yunel Escobar    5 navad002      Daniel Nava    7 troum001    Mike Trout    8   pujoa001
4 machm001   Manny Machado    5 jonea003       Adam Jones    8 davic003   Chris Davis    3   trumm001
5 burnb002     Billy Burns    8 lowrj001       Jed Lowrie    4 reddj001  Josh Reddick    9   valed001
6 forsl001  Logan Forsythe    4 morrl001   Logan Morrison    3 longe001 Evan Longoria    5   dickc002
    Eric_Hosmer_1 X3_11 morak001    Kendrys_Morales X10_1 gorda001     Alex_Gordon X7_2 peres002    Salvador_Perez
1 Corey Dickerson    10 jennd002   Desmond Jennings     7 millb002     Brad Miller    6 souzs001      Steven Souza
2  Starling Marte     7 cervf001 Francisco Cervelli     2 polag001 Gregory Polanco    9 harrj002     Josh Harrison
3   Albert Pujols    10 calhk001       Kole Calhoun     9 cronc002       C.J. Cron    3 simma001 Andrelton Simmons
4     Mark Trumbo     9 wietm001       Matt Wieters     2 alvap001   Pedro Alvarez   10 hardj003        J.J. Hardy
5  Danny Valencia     5 davik003        Khris Davis     7 butlb003    Billy Butler   10 canhm001        Mark Canha
6 Corey Dickerson    10 jennd002   Desmond Jennings     7 millb002     Brad Miller    6 souzs001      Steven Souza
  X2_2 infao001    Omar_Infante X4_3 fuenr001   Reymond_Fuentes X9_4 X_5 Y
1    9 kierk001 Kevin Kiermaier    8 congh001       Hank Conger    2     Y
2    4 mercj002    Jordy Mercer    6 lirif001 Francisco Liriano    1     Y
3    6 perec003    Carlos Perez    2 giavj001 Johnny Giavotella    4     Y
4    6 schoj001 Jonathan Schoop    4 rickj001      Joey Rickard    7     Y
5    3 vogts001    Stephen Vogt    2 semim001     Marcus Semien    6     Y
6    9 kierk001 Kevin Kiermaier    8 casac001       Curt Casali    2     Y


이로써 이번 포스팅을 마친다.


by Geol Choi | 


Comments