brunch

KBO를 LoL처럼! ELO Rating

타석단위의 승부를 점수화하여 랭킹을 매겨보자!

by randahlia

선수를 평가하는 지표는 그동안 너무나도 많은 형태로 개발되어 왔습니다. OPS, wRC, WAR등은 이제 너무나도 유명한 지표가 되어버렸지요. 제가 PAIGE라는 앱 서비스를 할때에도, 항상 무언가 허전한 부분이 있었습니다.


야구는 매 타석에서 승부가 결정되는데, 타석의 결과에서 비롯되는 상성 데이터는 어떻게 집계할수 있을까?


매 타석의 승부를 모두 집계한다면, 아마도 야구에서는 한 경기당 50개 이상의 승부가 나오게 됩니다. 홈 팀이 솔로홈런을 치고 1안타 퍼펙트 승리를 따낸다면 상대팀 27회 우리팀 24회의 공격을 하여 총 51번의 승부 데이터가 나오겠네요.

한 시즌에는 못해도 3만 5천회 이상의 승부가 기록되는 셈입니다. (실제로는 약 5만회 내외가 집계됩니다)


투수 A 가 타자 B를 이긴 결과가 있고, 타자 B가 투수 C를 이긴 결과가 있다면.

그리고 이런 결과가 여러개 모이게 되면....

투수 A와 투수 C에 대한 어떠한 상대적 지표를 만들수도 있지 않을까...

WAR로도 비교할수 없을땐 어떻게 할까...


이런 고민에서 시작했습니다.


ELO라는 개념은 Arpad Elo라는 체스선수이자 물리학자의 이름을 딴 랭킹 시스템 개념입니다.

좀더 쉽게 하자면, '스타크래프트 래더 점수제'가 좀더 쉬운 표현이겠네요. 아니면 'LoL 랭킹 시스템' 정도가 될거 같습니다.


KBO ELO는,

- 투수 타자 모두 1000점에서 시작한다

- 한 시즌이 끝나면 1000점을 기준으로 90%의 회귀를 실시한다.(1100점일 경우 1090점, 900점일 경우 910점으로 보정)

일단 이 두가지의 큰 틀을 갖고 시작합니다.


단순히 타자가 득점에 기여하는 행위(안타, 볼넷, 몸에맞는 공 등)를 한 것을 기준으로 삼을 경우, 타자의 승률이 40%가 채 되지 않기 때문에(2024년 리그 평균 출루율 0.352 -> 타자는 평균 35.2%의 승률을 가질 수 있음), 단순하게 접근하면 무조건 타자는 거의 0에 수렴하게 됩니다.


그래서 Run Expectancy 24 테이블에 기반하고, elo rating을 고려하는 xRV 라는 개념을 차용하여 레이팅 계산을 하는 방식으로 점수 계산식을 설계해 보았습니다. 이건 제가 한게 아니고, 역시나 미국의 똑똑하신 분들이 이미 개념을 소개해 놓았습니다.(Jacob Richey, playerELO, 2019참조)


기본 원리


ELO 레이팅 시스템은 타자와 투수의 대결 결과에 따라 양측의 레이팅 점수를 조정합니다:

- 타자가 좋은 결과를 얻으면 타자의 점수가 상승하고 투수의 점수가 하락합니다.

- 투수가 좋은 결과를 얻으면 투수의 점수가 상승하고 타자의 점수가 하락합니다.

- 변화량은 결과의 정도와 양측의 기존 레이팅 차이에 따라 결정됩니다.


초기 ELO 점수 설정


- **신규 타자**: 기본값 1000점 (`initial_batter_elo`)

- **신규 투수**: 기본값 1000점 (`initial_pitcher_elo`)


시즌 간 ELO 점수 회귀


- 이전 시즌 기록이 있는 선수는 그 ELO 점수를 기반으로 회귀 보정을 적용:

- 1000점과의 차이에 90%를 적용하여 회귀 보정

- 예시: 이전 시즌 1100점 → 신규 시즌 1090점 (회귀 보정)

- 투수의 경우 회귀 보정한 값이 투수 초기 ELO(1200)보다 낮으면 투수 초기 ELO 사용


타석 결과 평가 방식


각 타석의 결과는 RE24(Run Expectancy 24) 방식으로 평가됩니다:

- 주자 상황과 아웃 카운트에 따른 기대 득점 변화를 측정

- `run_value = re24_after - re24_before + 실제득점`


ELO 점수 업데이트 공식


레이팅 업데이트에는 기대 득점가치(Expected Run Value) 기반 공식을 사용합니다:


타자 Elo 변화량 = min(max((921.675 + (6046.370 * rv_diff) - prev_batter_elo) / 502, -k), k)

투수 Elo 변화량 = min(max((965.754 - (4762.089 * rv_diff) - prev_pitcher_elo) / 502, -k), k)

여기서 `rv_diff`는 실제 Run Value와 기대 Run Value의 차이를 나타냅니다.


조정 옵션


1. 동적 K값 조정 (`--use-dynamic-k`)

타석 수(매치업 수)에 따라 K값을 동적으로 조정합니다:

| 매치업 수 (누적) | K-value |

|-----------------|---------|

| 0 ~ 50회 | 20 |

| 51 ~ 100회 | 18 |

| 101 ~ 150회 | 16 |

| 151 ~ 200회 | 14 |

| 201 ~ 250회 | 12 |

| 251 ~ 300회 | 10 |

| 301 ~ 350회 | 8 |

| 351회 이상 | 6 |


K값이 작을수록 ELO 점수 변화가 적어집니다. 이는 많은 기록이 쌓인 안정적인 선수의 점수가 급격히 변하지 않도록 하는 기능입니다. 이는 기존 ELO 레이팅 시스템에서도 사용하고 있는 방식입니다. k값의 조정을 통해, 소위 '고인물'의 인플레 및 디플레(고여도 실력이 떨어지는 선수가 존재할수 있음) 가속화 현상을 억제합니다.


2. ELO 차이 기반 K값 조정 (`--use-elo-diff-k-adjustment`)

타자와 투수의 ELO 점수 차이와 Run Value 차이에 따라 K값을 조정합니다:


2-1. `rv_diff >= 0 && bELO > pELO`

- 투수가 언더독인 상황에서 타자가 좋은 결과를 낸 경우

- 원래 K값 사용 (multiplier 없음)


2-2. `rv_diff >= 0 && bELO < pELO`

- 타자가 언더독인 상황에서 타자가 좋은 결과를 낸 경우

- ELO 차이에 따른 K값 multiplier 적용:

- 0 ~ 50점: 원래 K값

- 51 ~ 100점: K값 × 1.5

- 101 ~ 150점: K값 × 2.0

- 151점 이상: K값 × 3.0 (최대 60점으로 제한)


2-3. `rv_diff < 0 && bELO > pELO`

- 투수가 언더독인 상황에서 투수가 좋은 결과를 낸 경우

- ELO 차이에 따른 K값 multiplier 적용 (2번과 동일)


2-4. `rv_diff < 0 && bELO < pELO`

- 타자가 언더독인 상황에서 투수가 좋은 결과를 낸 경우

- 원래 K값 사용 (multiplier 없음)


3. 균형 공식 사용 (`--use-balanced-formula`)


야구의 구조적 특성을 반영한 균형 공식을 사용합니다:

- 타자와 투수의 기대치에 가중치를 적용 (타자 50%, 투수 50%)

- 변화량 계산 분모 조정 (502)으로 변화 속도 조절

- 타자 유리 보정 (batter_advantage) 적용 가능


4. RE24테이블에 대한 상황별 계수 적용

rv_diff를 구하는 기반 공식에는 RE24테이블의 각 상황별 계수가 또 존재합니다. 대충

- elo 기반으로 투/타의 expected RV를 구함

- 실제 RE24테이블에서 해당 타석의 RE24_after 수치를 구함

- 그다음에 어쩌고저쩌고.. 2차방정식과 잡다한 무언가를 섞어 elo rating이 계산...


자료를 완벽하게 구할수 없어, 2023년 정규시즌과 2024년 정규시즌, 그리고 2025년 현재까지의 매 타석 데이터를 가지고 실험을 해 봤습니다. 대략 위 검은색의 가중치와 밸런스를 맞추니 투수와 타자 모두 800점 ~ 1200점 사이에서 950~1050점 사이에 두터운 선수층이 분포하는 일종의 정규분포 배치를 만들수 있었어요.


2023년, 그러니까 전체가 1000에서 시작했던 해의 탑 10은 아래와 같습니다

1743432273972.jpg

아시다시피 나성범 선수는 2023년 후반기에야 복귀했고, 이 점을 감안한다면 정말 '미친페이스'로 반년을 마쳤습니다. 2023년 올해의 투수상 수상자인 페디가 투수 파트의 1위를 차지했네요.

투수쪽에서 인상적인 부분은, 마무리도 선발도 아닌 김진성 선수입니다. 일단 알고리즘 상으로는 강한 선수와 붙어서 점수를 억제하는 것, 그리고 자신보다 아랫등급의 선수에게 점수를 내어주지 않는 것이 high elo rating의 유지 비법인데요, 2023년 김진성 선수는 정말 대단한 셋업맨이었다...라고 할수 있겠네요.


2024년은 이 점수들에서 90% 회귀한 숫자를 가지고 시작하게 됩니다. 2023년 데이터가 없는 선수들은 1000점에서 시작하겠지요. 그럼 2024년의 탑10을 보시겠습니다.

1743432640868.jpg

타자는 구자욱, 투수는 후라도 선수가 1위를 기록했습니다.

김도영이 윤정빈보다 낮은게 말이되느냐?????? 라고 하실게 뻔합니다.

맞습니다. 아직은 실험적인 데이터이고, 완벽하지 않습니다. 720경기 모두를 확보하지 못했고, 2023시즌은 10경기, 2024시즌은 9경기 정도의 데이터가 비어있습니다. 모종의 이유로 해당 데이터가 제대로 처리되지 않았습니다. 그러한 영향이 없다고 할 수 없습니다.


그리고 윤정빈 선수의 레이팅이 높은 것은, 짧은 타석 동안 본인보다 높은 점수의 투수들을 상대로 좋은 결과를 연속적으로 많이 냈을거라는 추측을 하게 만듭니다. 아래는 실제 윤정빈 선수의 2024년 elo 변동 그래프입니다.

1743433366502.jpg

80~120타석 사이에 점수가 급격하게 변하고 있습니다. 2024년 8월 슬래시라인이 356/482/622인데, 아마 그 기간 즈음이 아닐까 싶습니다.


제가 만든 elo rating은 실제로 다이나믹 하게 설계되었습니다.

언더독, 그러니까 신인이나 신규 선수가 레이팅 차이가 큰 선수와 맞붙어 좋은 결과를 내면 점수가 크게 상승하며, 반대로 상대방은 점수를 크게 잃습니다. 하지만 원래 이길것으로 예상되는 선수가 이길 경우에는 k값의 영향으로 점수의 상승폭이 매우 작아집니다.(시즌 초에는 점수의 변동폭이 20으로 시작하지만 풀타임 기준 350타석이 넘어서면 6점으로 줄어들게 됩니다. 물론 점수차가 큰 상대와 붙을 때는 최대 3배의 변동폭 증가가 생기게 됩니다) 그리고, RE 테이블을 기반으로 하기 때문에 타율 그 자체 보다는 '해당 상황의 득점 기대값 대비 얼마나 좋은 활약을 보여주었는가' 에 대한 부분을 더욱 많이 반영합니다. 만루에서 만루홈런을 치면 가장 점수가 높을 것이고, 만루에서 3중살을 치면 점수가 매우 많이 깎일겁니다. 만루에서 아웃이라도 당하지 않으면 최소한 1점은 낸 것이니 꽤나 많은 점수 상승이 있겠지요. 투수는 정 반대일 테고요. 결국 어느정도의 클러치 상황에 대한 가중치가 들어가는 계산법이라고 볼 수도 있습니다.


이러한 시스템을 만들다 보니, 아마도 논란이 많을 것이라고 생각합니다. 그래도 이런걸 만들어보는 이유는

이게 가장 한국인다운 지표

라고 생각하기 때문입니다.


비교하기 좋아하고, 뭐든 기준점에 놓고 또 비교하고 비교해야 하니, 이것만큼 재미있는게 있을까요.


오늘은 여기까지입니다.


또 뵙겠습니다.


계속해서 가다듬어 보겠습니다.

읽어주셔서 감사합니다.

keyword
매거진의 이전글토미존 수술의 혁신 - Internal Brace