04-20 07:13
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Data Science / Baseball] Lahman 데이터를 이용한 야구 데이터 분석 Part 1. - 데이터 준비 본문

Data Science/ Baseball Data Analysis

[Data Science / Baseball] Lahman 데이터를 이용한 야구 데이터 분석 Part 1. - 데이터 준비

cinema4dr12 2017. 3. 2. 22:32

Lahman 데이터를 이용한 야구 데이터 분석 Part 1. - 데이터 준비


본 포스팅에서는 Database Journalist인 Sean Lahman의 최신 데이터를 이용하여 MLB에 대한 분석을 시도해 보고자 한다. 처음에는 KBO 데이터를 분석해보고자 하였지만, 데이터를 얻기가 불편하고 초기 준비 단계가 많아 데이터 획득이 훨씬 수월하고 방대한 데이터를 보유하고 참고자료가 풍성한 MLB부터 시도해 보기로 하였다. 차후에는 KBO 데이터를 획득부터 분석까지 시도해 보기록 하겠다.



분석 환경은 가장 인기있는 통계처리 언어 중 하나인 R을 이용하였으며 버전은 다음과 같다:


> version
               _                           
platform       x86_64-w64-mingw32          
arch           x86_64                      
os             mingw32                     
system         x86_64, mingw32             
status                                     
major          3                           
minor          3.2                         
year           2016                        
month          10                          
day            31                          
svn rev        71607                       
language       R                           
version.string R version 3.3.2 (2016-10-31)
nickname       Sincere Pumpkin Patch


MLB 데이터 준비

Sean Lahman은 lahman이라는 R 패키지를 제공하고 있으나, 최신 데이터 기록은 2015년도이므로, 이 글을 쓰는 기준으로 최신 기록(2016년까지의 기록)을 Lahman의 홈페이지로부터 CSV 파일(2017년2월26일에 업데이트 되었음)을 다운받았다.


다운로드 링크: 2016-comma-delimited version


다운받은 파일을 압축해제하면 core 폴더 안에 여러가지의 .csv 파일을 볼 수 있을 것이다.

각 파일에 대한 설명은 readme2014.txt 파일을 참고하면 되지만, 야구 관련 인덱스를공부하는 차원에서 다음과 같이 정리해 보았다.


Master Table

 인덱스

 설 명

 playerID

 각 선수에게 할당된 고유식별자. playerID는 이 파일의 데이터를 다른 파일의

 기록과 연결함.

 birthYear

 태어난 년

 birthMonth

 태어난 월

 birthDay

 태어난 일

 birthCountry

 태어난 나라

 birthState

 태어난 주

 birthCity

 태어난 도시

 deathYear 죽은 년
 deathMonth 죽은 월
 deathDay 죽은 일
 deathCountry 죽은 나라
 deathState 죽은 주
 deathCity 죽은 도시
 nameFirst

 이름(Firstname)

 nameLast 성(Lastname)
 nameGiven

 Givenname(보통 Middlename + Firstname)

 weight 몸무게
 height

 키(인치)

 bats 좌타/우타/양손타자
 throws 우투/좌투
 debut 메이저리그 데뷔일
 finalGame

 마지막 출장일 (현재 활동 중인 경우 빈칸)

 retroID retrosheet이 사용하는 ID
 bbrefID

 Baseball Reference website가 사용하는 ID


Batting Table - 타격

 인덱스

 설 명

 playerID

 선수 ID

 yearID

 해당년도

 stint

 활동기간 (시즌 내 출장순서)

 teamID

 팀 ID

 lgID

 리그 ID

 G

 경기

 AB

 타석

 R

 득점

 H

 안타

 2B

 2루타

 3B 3루타
 HR 홈런
 RBI 타점
 SB 도루
 CS 도루실패
 BB 볼넷
 SO 삼진
 IBB 고의사구
 HBP 볼에 맞는 볼
 SH 희생번트
 SF 희생플라이
 GIDP 땅볼 병살


Pitching Table - 투구

 인덱스

 설 명

 playerID

 선수 ID

 yearID

 해당년도

 stint

 활동기간

 teamID

 팀 ID

 lgID

 리그 ID

 W

 승

 L

 패

 G

 경기

 GS

 선발경기

 CG 완투
 SHO 완봉
 SV 세이브
 IPOuts

 아웃수 (이닝수 x 3)

 H 안타허용
 ER 득점 허용(자책)
 HR 홈런 허용
 BB

 볼넷 허용

 SO 탈삼진
 BAOpp 상대타자 타율
 ERA 방어율
 IBB 고의사구
 WP

 폭투

 HBP 몸에 맞는 볼
 BK 보크
 BFP 상대한 타자 수
 GF 마무리 경기 수
 R 득점허용(자책 + 비자책)
 SH 희생번트 허용 
 SF 희생플라이 허용
 GIDP 탈 땅볼병살


Fielding Table - 수비

 인덱스

 설 명

 playerID 선수 ID
 yearID 해당년도
 stint 활동기간
 teamID 팀 ID
 lgID

 리그 ID

 Pos 포지션

 G

 경기

 GS

 선발경기

 InnOuts

 아웃카운트로 표현되는 필드 출장 시간

 PO

 획득한 아웃카운트

 A

 필드 어시스트

 E

 에러

 DP

 병살

 PB

 Passed Balls (포수만 해당)

 WP

 폭투 (포수만 해당)

 SB 도루 허용 (포수만 해당)
 CS 도루 저지 (포수만 해당)
 ZR Zone Rating


AllstarFull Table - 올스타

 인덱스

 설 명

 playerID

 선수 ID

 YearID

 해당년도

 gameNum

 경기 수

 gameID

 경기 ID

 teamID

 팀 ID

 lgID

 리그 ID

 GP

 경기출장한 경우 1

 startingPos

 선발로 출장한 경우 포지션


HallOfFame Table - 명예의 전당

 인덱스

 설 명

 playerID

 선수 ID

 yearID

 투표년도

 votedBy

 선수가 투표한 방법 

 ballots

 해당년도에 전체 투표 수

 needed

 해당년도에 올스타 선발에 필요한 득표수

 votes

 총 득표수

 inducted

 선수가 득표에 의해 선출되었는지 여부(Y 또는 N) 

 category

 후보자가 선정된 부문

 needed_note

 특별 선출에 대한 자격 설명


Managers Table - 감독

인덱스 

설 명 

 playerID

 감독 ID

 yearID

 해당년도

 teamID

 팀 ID

 lgID

 리그 ID

 inseason

 매니저 보직 순위. 해당년도에 개인이 전체를 관리한 경우 0.

 그외의 경우, 감독의 보직 (1: 첫번째 매니저, 2: 두번째 매니저, ...)

 G

 감독한 경기수

 W

 승

 L

 패

 rank

 당해년도 팀의 최종 랭킹

 plyrMgr 선수 감독 ('Y'로 표시)


Teams Table

 인덱스

 설 명

 yearID

 해당년도

 lgID

 리그 ID

 teamID

 팀 ID

 franchID

 프랜차이즈 (TeamsFranchise Table과 연결)

 divID

 팀의 소속 디비전

 Rank

 최종 순위

 G

 경기수

 GHome

 홈경기수

 W

 승

 L 패
 DivWin

 디비전 승리 (Y 또는 N)

 WCWin

 와일드카드 승리 (Y 또는 N)

 LgWin 리그 승리 (Y 또는 N)
 WSWin 월드시리즈 승 (Y 또는 N)
 R 득점

 AB

 타석수
 H 안타
 2B 2루타
 3B 3루타
 HR 홈런
 BB 볼넷
 SO 삼진
 SB 도루성공
 CS 도루실패
 HBP 몸에 맞는 볼
 SF 희생플라이
 RA 득점허용 (자책 + 비자책)
 ER 득점허용 (자책)
 ERA 방어율
 CG 완투승
 SHO 완봉승
 SV 세이브
 IPOuts

 아웃 개수 (1이닝을 3개의 IPOuts로 계산)

 HA 안타허용
 HRA 홈런허용

 BBA

 볼넷허용

 SOA 탈삼진
 E 에러
 DP 탈병살
 FP 필딩 백분율
 name 팀의 전체 이름
 park 홈구장 이름
 attendance 홈구장 관객수
 BPF 타자들에 대한 3년간 구장 효과
 PPF 투수들에 대한 3년간 구장 효과
 teamIDBR Baseball Reference website가 사용하는 팀 ID
 teamIDlahman45

 Lahman 데이터베이스 버전 4.5가 사용하는 팀 ID

 teamIDretro Retrosheet이 사용하는 팀 ID


BattingPost Table - 포스트시즌 타격

 인덱스

 설 명

 yearID

 해당년도

 round

 플레이오프 레벨

 playerID

 선수 ID

 teamID

 팀 ID

 lgID

 리그 ID

 G

 경기

 AB

 타석

 H

 안타

 2B

 2루타

 3B

 3루타

 HR

 홈런

 RBI 타점
 SB 도루성공
 CS 도루실패
 BB

 볼넷

 SO 삼진
 IBB 고의사구
 HBP 몸에 맞는 볼
 SH 희생번트
 SF 희생플라이
 GIDP 땅볼 병살타


PitchingPost Table - 포스트시즌 투구

인덱스

설 명

 playerID

 선수 ID

 yearID

 해당년도

 round

 플레이오프 레벨

 teamID

 팀 ID

 lgID

 리그 ID

 W

 승

 L

 패

 G

 출장경기

 GS

 선발경기

 CG

 완투

 SHO 완봉
 SV 세이브
 IPOuts 아웃 개수 (1이닝을 3개의 IPOuts로 계산)
 H 안타허용
 ER 득점허용 (자책)
 HR 홈런허용
 BB

 볼넷

 SO 탈삼진
 BAOpp

 상대한 타자의 타율

 ERA 방어율
 IBB 고의사구
 WP 폭투

 HBP

 몸에 맞는 볼 허용
 BK 보크
 BFP 상대한 타자 수
 GF 경기 마무리 수
 R

 허용 득점 (자책 + 비자책)

 SH 희생번트 허용
 SF 희생플라이 허용
 GIDP

 땅볼 병살


TeamFranchises Table - 팀 프랜차이즈

 인덱스

설 명

 franchID

 프랜차이즈 ID

 franchName

 프랜차이즈 이름

 active

 팀이 현재 운영 중인지 여부 (Y 또는 N)

 NAassoc

 운영 당시 National Association 팀 프랜차이즈


FieldingOF Table - 외야수비

인덱스

설 명

 playerID

 선수 ID

 yearID

 해당년도

 stint

 활동기간

 Glf

 좌익수로 출장한 경기

 Gcf

 중견수로 출장한 경기

 Grf

 우익수로 출장한 경기


ManagersHalf Table - 감독에 대한 스플릿 시즌 데이터

인덱스

설 명

 playerID

 감독 ID

 yearID

 해당년도

 teamID

 팀 ID

 lgID

 리그 ID

 inseason

 매니저 보직 순위. 해당년도에 개인이 전체를 관리한 경우 0.

 그외의 경우, 감독의 보직 (1: 첫번째 매니저, 2: 두번째 매니저, ...)

 half

 시즌 전반기 또는 후반기

 G

 경기수

 W

 승

 L

 패

 rank

 전/후반기 팀의 순위


TeamsHalf Table - 팀의 스플릿 시즌 데이터

인덱스

설 명

 yearID

 해당년도

 lgID

 리그 ID

 teamID

 팀 ID

 half

 시즌 전반기/후반기

 divID

 디비전

 DivWin

 디비전 승리 여부 (Y 또는 N)

 rank

 전/후반기 팀의 순위

 G

 경기 수

 W

 승

 L

 페


Salaries Table - 연봉

인덱스

설 명

 yearID

 해당년도

 teamID

 팀 ID

 lgID

 리그 ID

 playerID

 선수 ID

 salary

 연봉


SeriesPost Table - 포스트시즌

인덱스

설 명

 yearID

 해당년도

 round

 플레이오프 레벨

 teamIDwinner

 시리즈를 승리한 팀 ID

 lgIDwinner

 시리지를 승리한 팀의 리그 ID

 teamIDloser

 시리즈를 패한 팀 ID

 lgIDloser

 시리즈를 패한 리그 ID

 wins

 시리즈를 승리한 팀의 승 수

 losses

 시리즈를 패한 팀의 패 수

 ties

 시리즈 무승부 수


AwardsManagers Table - 감독 수상

인덱스

설 명

 playerID

 선수 ID

 awardID

 어워드 ID

 yearID

 해당년도

 lgID

 리그 ID

 tie

 공동수상 여부 (Y 또는 N)

 notes

 해당 어워드에 대한 주석


AwardsPlayers Table - 선수 수상

인덱스

설 명

 playerID

 선수 ID

 awardID

 수상 ID

 yearID

 해당년도

 lgID

 리그 ID

 tie

 공동수상 여부 (Y 또는 N)

 notes

 해당 어워드에 대한 주석



AwardsShareManagers Table - 감독상에 대한 투표

인덱스

설 명

 awardID

 투표한 어워드 이름

 yearID

 해당년도

 lgID

 리그 ID

 playerID

 선스 ID

 pointsWon

 획득 포인트

 pointsMax 가능한 최대 포인트 수
 votesFirst 1등 득표 수


AwardsSharePlayers Table - 선수상에 대한 투표

인덱스

설 명

 awardID

 투표한 어워드 이름

 yearID

 해당년도

 lgID

 리그 ID

 playerID

 선수 ID

 pointsWon

 획득 포인트

 pointsMax 가능한 최대 포인트 수
 votesFirst

 1등 득표 수


FieldingPost Table - 포스트시즌 수비

 인덱스

 설 명

 playerID 선수 ID
 yearID 해당년도
 teamID 팀 ID
 lgID 리그 ID
 round

 플레이오프 레벨

 Pos 포지션

 G

 출장경기 수

 GS

 선발출장경기 수

 InnOuts

 아웃카운트로 표현되는 필드 출장 시간

 PO

 생산한 아웃 수

 A

 필드 어시스트

 E

 에러

 DP

 병살 수

 TP

 삼중살 수

 PB

 패스트(Passed) 볼 (포수만 해당)

 SB 도루 허용 수 (포수만 해당)
 CS 도루 저지 수 (포수만 해당)


Appearances Table - 출장

 인덱스

 설 명

 yearID

 해당년도

 playerID

 선수 ID

 teamID 팀 ID
 lgID

 리그 ID

 G_all

 전체 출장경기 수

 GS 선발출장 수
 G_batting 타자로 출장한 경기 수
 G_defense 수비로 출장한 경기 수
 G_p 투수로 출장한 경기 수
 G_c 포수로 출장한 경기 수
 G_1b 1루수로 출장한 경기 수
 G_2b 2루수로 출장한 경기 수
 G_3b 3루수로 출장한 경기 수
 G_ss 유격수로 출장한 경기 수
 G_lf 좌익수로 출장한 경기 수
 G_cf

 중견수로 출장한 경기 수

 G_rf 우익수로 출장한 경기 수
 G_of 외야수로 출장한 경기 수
 G_dh

 지명타자로 출장한 경기 수

 G_ph 대타로 출장한 경기 수
 G_pr 대주자로 출장한 경기 수


Schools Table - 학교(~고등학교)

 인덱스

 설 명

 schoolID 학교 ID
 schoolName

 학교 이름

 schoolCity 학교가 속한 도시
 schoolState

 학교기 속한 주

 schoolNick

 학교 야구팀의 별명


CollegePlaying Table - 대학교

 인덱스

 설 명

 playerid 선수 ID
 schoolID

 학교 ID

 year 년도


R의 Working Directory 구조

본 포스팅을 설명하기 위해 Working Directory의 다음과 같은 구조를 갖도록 한다.





만약 각자의 Working Directory 구조가 제시한 구조와 다를 경우 연관 파일을 찾지 못할 수도 있으므로 가급적 구조를 동일하게(디렉터리 이름 포함) 가져가기를 권장한다.


MongoDB에 데이터 삽입 (Optional)

본 튜토리얼에서는 Lahman 데이터 전부를 MongoDB에 삽입하여 사용하도록 하겠다.

Optional이라고는 했지만 본 튜토리얼의 진행을 DB를 통해 데이터를 읽는 형식으로 진행할 예정이니 필수라고도 볼 수 있겠다.


물론, R의 빌트-인(Built-in) 함수인 read.csv() 등을 사용하여 .csv 파일들을 Data Frame 형식으로 불러올 수도 있겠지만 향후 지속적인 데이터 리소스 관리 측면에서 DB를 활용하는 것을 권장한다(꼭 MongoDB일 필요는 없다).


R에서 MongoDB를 연동하는 방법은 R과 MongoDB 연동하기를 참고하기 바란다.


위의 링크를 읽어 볼 시간이 없는 경우, MongoDB에 데이터 삽입을 설명하는 것이 본 포스팅의 목적이 아니므로 다음 R 코드들을 [Sources] 경로에 작성하고 실행하면 된다.


*주의사항:  코드 실행 시 반드시 해당 경로가 Working Directory로 지정되어야 한다.


MongoDB가 실행되어 있다고 가정하고, 다음 두 개의 코드를 실행해 보도록 한다.


R CODE: Connect.R

##############################################################################
# Connect.R
##############################################################################
# @Author: Geol Choi, ph.D
# @Date: Mar.4,2017
# @Description: To connect MongoDB & insert data
##############################################################################

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


R CODE: InsertData.R

##############################################################################
# InsertData.R
##############################################################################
# @Author: Geol Choi, ph.D
# @Date: Mar.4,2017
# @Description: To insert Lahman data into MongoDB
##############################################################################
base::rm(list = ls())
base::gc()

## intall packages & load them
base::source('./Connect.R', echo=FALSE)

basePath <- "../data/baseballdatabank-master/core/"
fileList <- base::list.files(basePath, pattern = NULL, all.files = TRUE)

## insert csv files
for(i in 3:base::length(fileList)) {
  fileName <- fileList[i];
  splitName <- base::strsplit(fileName, "[.]");
  colName <- splitName[[1]][1];
  extName <- splitName[[1]][2];
  
  # if file extension is csv then insert this into MongoDB
  if(extName == "csv") InsertDB(colName, basePath);
}


실행결과

Complete! Processed total of 5148 rows.
Complete! Processed total of 102761 rows.
Complete! Processed total of 179 rows.
Complete! Processed total of 6158 rows.
Complete! Processed total of 425 rows.
Complete! Processed total of 6879 rows.
Complete! Processed total of 102816 rows.
Complete! Processed total of 13543 rows.
Complete! Processed total of 17350 rows.
Complete! Processed total of 136815 rows.
Complete! Processed total of 12028 rows.
Complete! Processed total of 31291 rows.
Complete! Processed total of 12714 rows.
Complete! Processed total of 4156 rows.
Complete! Processed total of 3006 rows.
Complete! Processed total of 3436 rows.
Complete! Processed total of 93 rows.
Complete! Processed total of 19105 rows.
Complete! Processed total of 249 rows.
Complete! Processed total of 44963 rows.
Complete! Processed total of 5271 rows.
Complete! Processed total of 26428 rows.
Complete! Processed total of 1207 rows.
Complete! Processed total of 316 rows.
Complete! Processed total of 2835 rows.
Complete! Processed total of 120 rows.
Complete! Processed total of 52 rows.


데이터가 잘 입력되었는지 확인하려면 Command Line Tool에서 다음 명령을 입력해 본다:


> mongo
MongoDB shell version v3.4.2
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.2
Server has startup warnings:
2017-03-04T19:22:17.660+0900 I CONTROL  [initandlisten]
2017-03-04T19:22:17.660+0900 I CONTROL  [initandlisten] ** WARNING: Access contr
ol is not enabled for the database.
2017-03-04T19:22:17.661+0900 I CONTROL  [initandlisten] **          Read and wri
te access to data and configuration is unrestricted.
2017-03-04T19:22:17.661+0900 I CONTROL  [initandlisten]
2017-03-04T19:22:17.661+0900 I CONTROL  [initandlisten] Hotfix KB2731284 or late
r update is not installed, will zero-out data files.
2017-03-04T19:22:17.662+0900 I CONTROL  [initandlisten]
> show dbs
admin     0.000GB
baseball  0.042GB
local     0.000GB
> use baseball
switched to db baseball
> db.getCollectionNames()
[
        "AllstarFull",
        "Appearances",
        "AwardsManagers",
        "AwardsPlayers",
        "AwardsShareManagers",
        "AwardsSharePlayers",
        "Batting",
        "BattingPost",
        "CollegePlaying",
        "Fielding",
        "FieldingOF",
        "FieldingOFsplit",
        "FieldingPost",
        "HallOfFame",
        "HomeGames",
        "Managers",
        "ManagersHalf",
        "Master",
        "Parks",
        "Pitching",
        "PitchingPost",
        "Salaries",
        "Schools",
        "SeriesPost",
        "Teams",
        "TeamsFranchises",
        "TeamsHalf"
]


MongoDB로부터 데이터 불러오기

성공적으로 MongoDB에 Lahman 데이터를 모두 저장하였다면 이제 데이터를 불러오는 함수를 작성하여 보자.


앞서 저장된 데이터를 Document Collection으로 구성되어 있으며, 이를 불러오는 코드는 다음과 같다.


R CODE: ImportCollection.R

##############################################################################
# ImportCollection.R
##############################################################################
# @Author: Geol Choi, ph.D
# @Date: Mar.4,2017
# @Description: To import document collection from MongoDB
##############################################################################
source('./Connect.R', echo=FALSE)

ImportCollection <- function(colName) {
  con <- Connect(colName);
  df <- con$find(query = '{}');
  rm(con);
  
  return(df);
}

DB로부터 "Master"라는 이름의 Collection을 불러와 보도록 한다. 이는 "Master.csv"라는 Lahman 데이터 파일로부터 생성된 것이며, 각 선수의 주요정보가 기록된 데이터이다.


R CODE: MasterTable.R

source('./ImportCollection.R', echo=FALSE)

## import Master
master <- ExtractCollection("Master")
head(master)


맺음말

이제 Lahman 데이터를 이용하여 2016까지의 MLB 데이터를 분석할 준비를 완료하였다.

다음 포스팅에서는 본격적으로 데이터를 분석해 보도록 하겠다.


by Geol Choi | 

Comments