야구 분석/R

미키 맨틀의 커리어 살펴보기

sam_j_s 2024. 8. 22. 15:24
728x90
반응형

주제

R 시스템은 데이터에 통계 모델을 적용하는 데 매우 적합합니다. 세이버메트릭스에서 자주 다루는 주제 중 하나는 MLB 데뷔부터 은퇴까지의 선수 시즌 타격, 수비 또는 투구 통계의 상승과 하락입니다. 일반적으로 대부분의 선수들이 20대 후반에 전성기를 맞이한다고 믿어지지만, 일부 선수들은 더 늦은 나이에 전성기를 맞이하는 경향이 있습니다. 선수의 커리어 궤적을 모델링하는 간단한 방법은 이차 함수 또는 포물선 곡선을 사용하는 것입니다. R의 lm() (선형 모델) 함수를 사용하면, 선수의 나이와 OPS 통계를 통해 이 모델을 쉽게 적용할 수 있습니다.

 

유명한 선수의 커리어 궤적을 살펴보겠습니다. 미키 맨틀은 19세에 뉴욕 양키스에서 큰 영향을 미쳤고, 빠르게 성장하여 최고의 타자 중 한 명이 되었습니다. 그러나 부상으로 인해 성적은 점점 하락하였고, 36세에 은퇴할 때까지 그의 타격 능력은 떨어졌습니다. 이차 모델을 사용하여 맨틀의 전성기 나이, 커리어 하이, 그리고 성적의 향상과 하락 속도를 정의할 수 있습니다.

 

미키 맨틀의 타격 궤적

커리어 궤적을 살펴보기 위해, 위대한 슬러거 미키 맨틀의 타격 데이터를 분석해보겠습니다. 시즌별 타격 통계를 얻기 위해 Lahman 패키지를 로드합니다. 이 패키지에는 People과 Batting 데이터 프레임이 포함되어 있습니다. 또한, tidyverse 패키지도 함께 로드합니다.

library(tidyverse)
library(Lahman)

 

먼저 People 데이터 프레임에서 미키 맨틀의 playerID를 추출합니다. filter() 함수를 사용하여 nameFirst가 "Mickey"이고 nameLast가 "Mantle"인 행을 찾습니다. 그의 playerID는 벡터 mantle_id에 저장됩니다.

mantle_id <- People |> 
  filter(nameFirst == "Mickey", nameLast == "Mantle") |>
  pull(playerID)

 

하나의 문제는 SF(희생 플라이)와 HBP(데드볼)와 같은 특정 통계가 이전 시즌에는 기록되지 않았으면 현재는 NA로 표시된다는 점입니다. 이러한 결측값을 0으로 대체해주겠습니다.

batting <- Batting |>
  replace_na(list(SF = 0, HBP = 0))

 

각 시즌에 대한 미키 맨틀의 나이를 계산하기 위해, 그의 출생 연도가 People 데이터 프레임에 포함되어 있습니다. 메이저 리그 베이스볼에서는 선수의 나이를 특정 시즌의 6월 30일 기준으로 정의합니다.

 

맨틀의 타격 통계를 얻기 위해 사용자 정의 함수 get_stats()를 사용합니다. 이 함수의 입력은 선수의 playerID이며, 출력은 선수의 타격 통계를 포함하는 데이터 프레임입니다. 이 함수는 모든 시즌에 대한 선수의 나이(변수 Age), 슬러깅 비율(SLG), 출루율(OBP), 그리고 OPS를 계산합니다.

get_stats <- function(player_id) {
  batting |> 
    filter(playerID == player_id) |>
    inner_join(People, by = "playerID") |>
    mutate(
      birthyear = if_else(
        birthMonth >= 7, birthYear + 1, birthYear
      ),
      Age = yearID - birthyear,
      SLG = (H - X2B - X3B - HR + 2 * X2B + 3 * X3B + 4 * HR) / AB,
      OBP = (H + BB + HBP) / (AB + BB + HBP + SF),
      OPS = SLG + OBP
    ) |>
    select(Age, SLG, OBP, OPS)
}

 

get_stats() 함수를 R에 읽어들인 후, mantle_id를 입력으로 하여 맨틀의 통계를 얻습니다. 생성된 타격 통계 데이터 프레임은 Mantle이라는 이름으로 저장됩니다.

Mantle <- get_stats(mantle_id)

타격 성과를 측정하는 좋은 방법 중 하나는 OPS(출루율 + 슬러깅 비율)입니다. 미키 맨틀의 OPS 시즌 값이 나이에 따라 어떻게 변하는지를 알아보려면, ggplot2를 사용하여 나이에 대한 OPS의 산점도를 구성합니다.

ggplot(Mantle, aes(Age, OPS)) + geom_point()

그림 1 . 미키 맨틀의 나이에 따른 OPS 산점도

그림 1을 보면 미키 맨틀의 OPS 값이 19세에서 20대 후반까지 증가하는 경향이 있으며, 이후 36세에 은퇴할 때까지 일반적으로 감소하는 것이 분명합니다. 이러한 상승과 하강의 관계를 모델링하기 위해 부드러운 곡선을 사용할 수 있습니다. 이 곡선은 맨틀의 커리어 타격 궤적을 이해하고 요약하는데 도움이 되며, 맨틀의 궤적을 유사한 타격 성과를 가진 다른 선수들과 비교하는 데 용이합니다.

 

편리한 부드러운 곡선의 선택은 다음 형태의 이차 함수입니다.

$$A + B(Age - 30) + C(Age-30)^2$$

상수 A, B, C는 곡선이 산점도의 점들과 가장 잘 일치하도록 선택됩니다.이 이차 곡선은 사용하기 쉬운 다음과 같은 장점을 가지고 있습니다.

  1. 상수 A는 선수가 30세일 때 예측된 OPS 값입니다.
  2. 이 함수는 최대 값에 도달합니다$$PEAK_{-}AGE = 30 -\frac{B}{2C}$$ 이것은 선수가 그의 커리어 중 전성기 타격 성과를 보이는 나이입니다.
  3. 곡선의 최대 값은 $$MAX = A - \frac{B^2}{4c}$$ 이는 선수의 커리어 전체에서 추정되는 최대 OPS 입니다.
  4. 계수 C는 일반적으로 음수 값을 가지며, 이차 함수의 곡률 정도를 나타냅니다. 선수가 큰 값의 C를 가진 경우, 이는 그가 더 빠르게 전성기에 도달하고 은퇴까지 더 빠르게 능력이 감소함을 나타냅니다. 간단한 해석으로 C가 전성기 나이에서 1년 후까지 OPS의 변화를 나타낸다고 할 수 있습니다.

새로운 함수 fit_model()을 작성하여 이 이차 곡선을 선수의 타격 데이터에 맞춥니다. 이 함수의 입력은 선수의 타격 통계가 포함된 데이터 프레임 dd이며, 이 데이터 프레임에는 변수 Age와 OPS가 포함됩니다. 함수 lm()을 사용하여 이차 곡선을 적합시킵니다.

$$OPS\sim I(Age-30) + I((Age-30)^2)$$

이 공식은 OPS가 반응 변수이며, (Age - 30)과 (Age - 30)^2가 예측 변수임을 나타냅니다. 추정된 계수 A, B, C는 coef() 함수를 사용하여 벡터 b에 저장됩니다. 전성기 나이와 최대 값은 각각 변수 Age_max와 Max에 저장됩니다.

fit_model <- function(d) {
  fit <- lm(OPS ~ I(Age - 30) + I((Age - 30)^2), data = d)
  b <- coef(fit)
  Age_max <- 30 - b[2] / b[3] / 2
  Max <- b[1] - b[2] ^ 2 / b[3] / 4
  list(fit = fit, Age_max = Age_max, Max = Max)
}

 

그런 다음, fit_model() 함수를 맨틀의 데이터 프레임에 적용합니다. 이 함수의 출력 에는 이차 곡선 적합에 대한 모든 계산을 저장하는 객체가 포함됩니다. 추가로, 이 함수는 전성기 나이와 최대 값을 출력합니다. 다음 코드에서 이 값을 확인할 수 있습니다.

F2 <- fit_model(Mantle)
F2 |>
  pluck("fit") |>
  coef()

c(F2$Age_max, F2$Max)

최적의 곡선 적합은 다음과 같습니다.

$$1.04313 - 0.02288(Age - 30) - 0.00387(Age - 30)^2$$

이 모델을 사용하여, 맨틀은 27세에 전성기를 맞이하며, 곡선에서 최대 OPS는 1.08로 추정됩니다. 곡률 매개변수의 추정 값은 -0.00387로, 전성기 나이에서 1년 더 나이가 들었을 때 맨틀의 OPS 감소량은 0.00387입니다.

 

최적의 이차 곡선을 산점도에 추가합니다. geom_smooth() 함수는 나이 값의 시퀀스에 따라 맨틀의 OPS를 곡선으로 추정하고, 이 값을 현재 그래프에 선으로 오버레이합니다. geom_vline()과 geom_hline() 함수는 각각 전성기 나이와 최대 값을 나타내는 위치를 표시하며, annotate() 함수는 이 값들을 레이블로 표시합니다. 결과 그래프는 그림 2에 표시됩니다.

ggplot(Mantle, aes(Age, OPS)) + geom_point() +
  geom_smooth(
    method = "lm", se = FALSE, linewidth = 1.5,
    formula = y ~ poly(x, 2, raw = TRUE)
  ) +
  geom_vline(
    xintercept = F2$Age_max, 
    linetype = "dashed", color = "red"
  ) +
  geom_hline(
    yintercept = F2$Max,
    linetype = "dashed", color = "red"
  ) +
  annotate(
    geom = "text", x = c(29, 20), y = c(0.72, 1.1),
    label = c("Peak age", "Max"), size = 5,
    color = "red"
  )

그림 2 . 미키 맨틀의 OPS 커리어 궤적과 이차 스무딩 곡선에서 식별된 전성기 나이와 최대 OPS

 

최적의 이차 곡선에 초점을 맞추었지만, 적합 절차에 대한 더 많은 세부 사항은 lm()의 출력과 변수 F2에 저장됩니다. 이 적합의 일부 출력을 표시하기 위해 summary() 함수를 사용하여 요약을 찾습니다. 여기서는 리스트에서 항목을 검색하는 데 pluck() 함수를 사용하는 방법을 설명합니다.

F2 |> pluck("fit") |> summary()

$R^2$ 의 값은 0.602입니다. 이는 맨틀의 OPS 값 변동성의 약 60%가 이차 곡선으로 설명될 수 있음을 의미합니다. 잔차 표준 오차는 0.084입니다. 곡선으로부터의 수직 편차(잔차) 중 약 2/3가 ±1 잔차 표준 오차 사이에 위치합니다. 이 경우, 해석은 잔차의 약 2/3가 -0.084와 0.084 사이에 분포한다는 것입니다.

반응형

'야구 분석/R'의 다른글

  • 현재글 미키 맨틀의 커리어 살펴보기

관련글