원래는 예~전에 썼어야 했던 글인데 지금 올립니다. 또한 2024년 8월 2일 기준으로 이전 시뮬레이션에 약간의 실수를 발견해 수정했습니다. 죄송합니다.
2023년 말, 두산과 NC가 하마터면 상대 전적이 아닌 상대 경기 득실점으로 순위를 가를 뻔했습니다. (다행히도 마지막에 승차가 나긴 했습니다.) 그게 제가 PSodds에 득실점을 예측하기는 해야겠다고 생각한 계기가 되었습니다. 원래 PSodds의 시뮬레이션 절차에는 단지 '상대 승률'을 계산하는 부분만 있었습니다. 그렇기 때문에 굳이 상대 득실점을 고려하지는 않았고, 규정상에 있는 상대전적까지 같은 경우 순위 결정에 대한 부분은 그냥 편의적으로 평균 내서 계산하고 있었습니다. (예를 들어 같은 3위 승률 팀이 세 팀이고 상대전적도 같은 경우 각 팀의 3~5위 확률을 $\frac{1}{3}$씩 계산했다는 얘기입니다.) 설마 이 상황까지 오진 않겠지라고 생각했으니까요. 그런데 KBO는 그런 게 안 통하더군요. 10 구단 체제 이후로 확실히 결말의 다양성 자체가 증가한 느낌입니다. 제가 두 눈으로 이런 극한의 상황까지 봤기 때문에 득실점을 예측하는 부분을 PSodds 코드에 삽입할 필요성이 생겼습니다.
2023 시즌까지의 PSodds와 달라진 점은 먼저 득실점을 계산한다는 겁니다. 그렇기 때문에 16경기에 대한 상대승패만 시뮬레이션했던 과거에 비해 매 경기의 상대 득실점을 토대로 시뮬레이션 하다 보니 계산 시간이 좀 더 길어졌습니다. 물론 애초에 시뮬레이션 자체는 굉장히 빠르게 계산할 수 있었기 때문에 가장 계산 시간이 많이 드는 시즌 시작 전에 대해서도(남은 경기가 720경기이기 때문입니다.) 30초 이내에 계산이 끝납니다. 그리고 또 한 가지, 매 경기 득실점을 시뮬레이션 하다 보니 상대 득점과 실점이 같은 경우가 생기게 되고 기대되는 무승부 횟수도 계산할 수 있다는 겁니다. 계산해 본 결과 확실히 리그 평균 득점이 적은 경우 리그 평균 득점이 많은 경우에 비해 리그 무승부 횟수가 많게 계산됐습니다. 지난 몇 년과 같이 4.5점이 평균인 리그에서는 러프하게 5~10회 정도의 무승부가 기대되는 수준이었습니다. (한 팀당 평균 1회가 좀 넘는 수준이었습니다.)
문제는 득실점을 어떻게 예상하냐는 겁니다. 이런 극한 상황까지 가정하기 위해서는 앞으로 있을 경기의 득실점 향방도 어느 정도 고려할 수 있어야 하거든요. 그렇다면 득실점을 어떻게 예상할 수 있을까요? 먼저 말씀드릴 건 리그 차원의 앞으로의 기대 득점 수준을 시뮬레이션하는 건 제 능력으로는 무리입니다. 그렇다면 현재 수준의 기대 득점을 예상하되, 시즌 초반의 경우 전 시즌 기록과의 득점 수준 보정을 하는 방안을 쓸 수밖에 없습니다. 현재는 53경기를 기준으로 그전에는 전 시즌 기록과 현 시즌 기록을 보정하고 있고, 이후에는 현 시즌 기록을 그대로 시즌 예상 득/실점 수로 넣어 계산하고 있습니다. (53경기는 각 팀이 모든 상대 팀과 한 번씩 이상의 홈/원정 시리즈를 완료한 상황에서의 경기 수입니다.) 그렇다면 상대 득실점을 기대 승률처럼 계산해 볼 수 있을까요? 아래에서 살펴보도록 합시다.
상대승률 식과 기대 승률 식을 살펴봅시다. 팀 1의 기대승률을 $W_{1}$, 팀 1이 팀 2를 상대를 승리할 확률인 상대승률을 $W_{12}$라고 쓰기로 하겠습니다. (RS: 득점, RA: 실점)
$$W_{12} = \frac{W_{1}(1-W_{2})}{W_{1}+W_{2}-2W_{1}W_{2}} $$
$$W_{1} = \frac{{RS_{1}}^{1.83}}{{RS_{1}}^{1.83}+{RA_{1}}^{1.83}} = \frac{1}{1+({RA_{1}}/{RS_{1}})^{1.83}}$$
그리고 위의 기대승률 식을 생각해 본다면 $W_{12} = \frac{1}{1+(RA_{12}/RS_{12})^{1.83}}$로 표현 가능할 겁니다. 이제 좀 더 식을 들여다보죠.
$W_{12} = \frac{\frac{1}{[1+({RA}_{1}/{RS}_{1})^{1.83}]}\cdot \frac{({RA}_{2}/{RS}_{2})^{1.83}}{[1+({RA}_{2}/{RS}_{2})^{1.83}]}}{\frac{1}{[1+({RA}_{1}/{RS}_{1})^{1.83}]}+\frac{1}{[1+({RA}_{2}/{RS}_{2})^{1.83}]}-2\frac{1}{[1+({RA}_{1}/{RS}_{1})^{1.83}]}\cdot\frac{1}{[1+({RA}_{2}/{RS}_{2})^{1.83}]}} \\ \quad\;\;= \frac{({RA}_{2}/{RS}_{2})^{1.83}}{({RA}_{1}/{RS}_{1})^{1.83}+({RA}_{2}/{RS}_{2})^{1.83}} = \frac{1}{1+(\frac{{RA}_{1}\cdot{RS}_{2}}{{RS}_{1}\cdot{RA}_{2}})^{1.83}} \\ \quad\;\;= \frac{1}{1+({RA}_{12}/{RS}_{12})^{1.83}}$
그러니, $RS_{1}\cdot RA_{2}$는 $RS_{12}$와 비례하고 $RA_{1}\cdot RS_{2}$는 $RA_{12}$와 비례할 겁니다. 그리고 이를 리그 전체 상황에 대입, 전체 득실점과의 크기를 맞춰 줌으로써 득실점 모듈을 PSodds 계산 코드에 삽입할 수 있을 겁니다. (이후의 계산은 이전에 사용한 shooting method를 똑같이 사용한다고 생각하면 됩니다.)
다만 득실점의 분포가 어떻게 될지 예상해 봐야 할 겁니다. 여러 분포를 사용할 수 있겠지만, 저는 베이불 분포를 사용하기로 했습니다. 이는 스티븐 밀러(Steven J. Miller)가 피타고리안 기대승률의 타당성을 이야기할 때 사용한 분포이고, 피타고리안 승률과 실제 득실점 분포를 잘 묘사하는 분포이기 때문입니다. (Shape parameter는 피타고리안 승률을 계산할 때 처럼 1.83을 사용합니다.) 하지만 여기에서 살짝의 예외가 필요한데, 실제 경기는 9회 홈팀이 이기는지, 지는지에 따라 홈팀의 공격 이닝 횟수가 달라지기 때문입니다. 그렇기에 이런 상황의 경우 한 이닝의 득실점을 계산할 필요가 있는데, 이는 Tango Distribution으로 해결하기로 했습니다. Tango Distribution은 한 이닝에서 n실점을 할 확률(아래 식에서는 $f(n)$)을 계산하는데 다음과 같이 계산합니다.
$a=c\cdot {RI}^{2}\quad(RI=Runs/Inning)$
$f(0)=RI/(RI+a)$
$DR(Drop\;rate)=1-c\cdot f(0)$
$f(1)=(1-f(0))\cdot(1-DR)$
$f(n)=f(n-1)\cdot DR\quad(n\geq2)$
여기에서 c는 보통 이닝에서는 0.767을, 경기가 끝날 수 있는 상황(예: 9회 말, 연장 말 공격)에서는 0.852를 사용합니다. 다만 이건 톰 탱고가 썼던 상수고, 저는 KBO의 이닝별 기록을 기준으로 비교해서 각각의 상수로 0.746, 0.846을 사용하기로 했습니다.
위 그림 1. 은 Odds 5%를 기준으로 기대 승률 버전, 득실점 추가 버전, 그리고 coin flip 버전(상대 승률을 0.5로 고정)의 psodds 퍼포먼스를 비교한 그림입니다. 만약 psodds와 실제 포스트시즌 진출 확률이 완벽히 같다면 검은 점선을 따를 거고, 검은 점선에 가까울수록 psodds가 실제 포스트시즌 진출 확률을 잘 예상한다고 생각할 수 있을 겁니다. 전체적으로 psodds가 낮은 경우 시뮬레이션 된 psodds보다 실제 포스트시즌 진출 확률이 더 낮은 경향을 보이고 psodds가 높은 경우는 그 반대의 경향성을 보입니다. 다만 이건 팬그래프의 playoff odds에서도 똑같이 보이는 현상이고, 시뮬레이션으로는 설명할 수 없는 팀의 분위기 등에 의한 효과라고 볼 여지가 있습니다. 그걸 제외하고 본다면, coin flip버전보다는 과거/현 psodds가 확실히 더 좋은 퍼포먼스를 보인다는 걸 확인할 수 있습니다. 그에 비해 기대 승률 버전, 득실점 추가 버전의 psodds 경우 어떤 버전이 더 좋은 퍼포먼스를 보여준다고 딱 잘라 말하기는 어렵고 비슷한 수준이라고 할 수 있습니다.
아래 표는 월별로 기대 승률 버전과 득실점 추가 버전이 얼마나 차이가 있는지에 대한 표입니다. 시즌 초반에 차이가 좀 크지만 5월 이후에는 대체적으로 더 나은 퍼포먼스를 보여줍니다.
표 1. 2001~2023 월별 평균 MAE 변화, coin flip에서 PS odds 버전별 비교
시기 | Coin Flip | 기대 승률 버전 | 득실점 추가 버전 |
3~4월 | 0.445 | 0.433 | 0.438 |
5월 | 0.364 | 0.336 | 0.337 |
6월 | 0.286 | 0.262 | 0.261 |
7월 | 0.228 | 0.213 | 0.212 |
8월 | 0.160 | 0.151 | 0.149 |
9~10월 | 0.073 | 0.071 | 0.069 |
시즌 | 0.249 | 0.235 | 0.235 |
왜 3월, 4월이 이전 버전에 비해 퍼포먼스가 나쁘냐고 물어보실 수 있는데, 이는 이전과 달리 득실점을 계산하다 보니 나오는 현상입니다. 좀 더 설명하자면 득실점을 계산하면서 어쩔 수 없이 파크팩터를 계산에 사용하게 되는데, 그 때문에 파크팩터가 투수 친화구장인 경우(예: 잠실을 쓰는 LG, 두산) 홈구장에서의 득점력이 조금 약해집니다. 그 때문에 똑같이 홈/원정 보정을 넣어서 계산함에도 불구하고 예상 성적에서 약간 불리하게 계산이 되고, 시즌 초반 포스트시즌 진출 확률이 50%보다 작아지게 됩니다. 그에 비해 실제 결과는 두산의 예와 같이(2001~2023 시즌 중 17 시즌 포스트시즌 진출로 모든 팀 중 최다) 전력이 강한 경우가 많았기 때문에 시즌 초반의 예측의 결과는 오히려 coin flip 버전으로 계산하는 것보다도 조금 나쁘게 계산되었습니다. 하지만 시즌 중반 이후에는 오히려 득실점을 계산하는 경우가 더 퍼포먼스가 뛰어나고, 그 덕분에 시즌 전체로 보자면 아주 살짝 더 MAE가 작습니다. (이전 버전 0.23499 vs 득실점 추가 버전 0.23483) 다만 딱히 차이가 난다고 할 수 없는 수준이고, 시즌 후반에 대한 설명력이 좀 더 강해졌다 수준으로 이해하시면 될 것 같습니다.
득실점 추가 버전(2001~2023)
PSodds(P) | 횟수 | 시뮬레이션 | 실제 진출 확률 |
P<0.05 | 7083 | 0.009 | 0.009 |
0.05<=P<0.10 | 1566 | 0.074 | 0.050 |
0.10<=P<0.15 | 1277 | 0.124 | 0.089 |
0.15<=P<0.20 | 1277 | 0.175 | 0.152 |
0.20<=P<0.25 | 1222 | 0.225 | 0.201 |
0.25<=P<0.30 | 1149 | 0.274 | 0.262 |
0.30<=P<0.35 | 1298 | 0.326 | 0.345 |
0.35<=P<0.40 | 1450 | 0.376 | 0.345 |
0.40<=P<0.45 | 1734 | 0.426 | 0.393 |
0.45<=P<0.5 | 1953 | 0.475 | 0.454 |
0.50<=P<0.55 | 1927 | 0.524 | 0.528 |
0.55<=P<0.60 | 1659 | 0.574 | 0.564 |
0.60<=P<0.65 | 1353 | 0.625 | 0.633 |
0.65<=P<0.70 | 1148 | 0.675 | 0.672 |
0.70<=P<0.75 | 1056 | 0.725 | 0.75 |
0.75<=P<0.80 | 1058 | 0.775 | 0.815 |
0.80<=P<0.85 | 1070 | 0.824 | 0.888 |
0.85<=P<0.90 | 1158 | 0.876 | 0.931 |
0.90<=P<0.95 | 1409 | 0.925 | 0.956 |
0.95<=P<1.00 | 4721 | 0.987 | 0.994 |
P=1 | 2547 | 1.000 | 1.000 |
기대 승률 버전(2001~2023)
PSodds(P) | 횟수 | 시뮬레이션 | 실제 진출 확률 |
P<0.05 | 7156 | 0.009 | 0.008 |
0.05<=P<0.10 | 1545 | 0.074 | 0.059 |
0.10<=P<0.15 | 1312 | 0.125 | 0.090 |
0.15<=P<0.20 | 1260 | 0.176 | 0.160 |
0.20<=P<0.25 | 1269 | 0.225 | 0.219 |
0.25<=P<0.30 | 1123 | 0.276 | 0.282 |
0.30<=P<0.35 | 1295 | 0.326 | 0.354 |
0.35<=P<0.40 | 1426 | 0.376 | 0.330 |
0.40<=P<0.45 | 1656 | 0.426 | 0.377 |
0.45<=P<0.50 | 1830 | 0.475 | 0.446 |
0.50<=P<0.55 | 1903 | 0.522 | 0.523 |
0.55<=P<0.60 | 1489 | 0.574 | 0.575 |
0.60<=P<0.65 | 1390 | 0.624 | 0.617 |
0.65<=P<0.70 | 1228 | 0.675 | 0.694 |
0.70<=P<0.75 | 1053 | 0.725 | 0.745 |
0.75<=P<0.80 | 1082 | 0.775 | 0.817 |
0.80<=P<0.85 | 1074 | 0.824 | 0.876 |
0.85<=P<0.90 | 1194 | 0.876 | 0.925 |
0.90<=P<0.95 | 1364 | 0.925 | 0.973 |
0.95<=P<1.00 | 4985 | 0.987 | 0.987 |
P=1 | 2334 | 1.000 | 1.000 |
Coin Flip 버전(2001~2023)
PSodds(P) | 횟수 | 시뮬레이션 | 실제 진출 확률 |
P<0.05 | 6148 | 0.008 | 0.003 |
0.05<=P<0.10 | 1436 | 0.074 | 0.047 |
0.10<=P<0.15 | 1342 | 0.124 | 0.050 |
0.15<=P<0.20 | 1321 | 0.174 | 0.107 |
0.20<=P<0.25 | 1241 | 0.225 | 0.160 |
0.25<=P<0.30 | 1245 | 0.276 | 0.260 |
0.30<=P<0.35 | 1365 | 0.326 | 0.300 |
0.35<=P<0.40 | 1593 | 0.376 | 0.335 |
0.40<=P<0.45 | 1978 | 0.426 | 0.388 |
0.45<=P<0.50 | 2266 | 0.475 | 0.459 |
0.50<=P<0.55 | 2333 | 0.523 | 0.545 |
0.55<=P<0.60 | 1829 | 0.574 | 0.553 |
0.60<=P<0.65 | 1517 | 0.624 | 0.651 |
0.65<=P<0.70 | 1259 | 0.675 | 0.724 |
0.70<=P<0.75 | 1147 | 0.725 | 0.805 |
0.75<=P<0.80 | 1055 | 0.775 | 0.874 |
0.80<=P<0.85 | 1042 | 0.825 | 0.914 |
0.85<=P<0.90 | 1163 | 0.876 | 0.957 |
0.90<=P<0.95 | 1263 | 0.927 | 0.976 |
0.95<=P<1.00 | 4285 | 0.987 | 0.989 |
P=1 | 2160 | 1.000 | 1.000 |
5. 실제 결과와의 비교 - UPDATE (3) | 2023.06.18 |
---|---|
3. 홈/원정 경기 승률 조정 - UPDATE (0) | 2023.06.18 |
5. 실제 결과와의 비교 (0) | 2022.02.18 |
4. 평균으로의 회귀 적용 (1) | 2022.02.13 |
3. 홈/원정 경기 승률 조정 (0) | 2022.02.13 |
댓글 영역