야구에서는 매 경기마다 수많은 기록과 데이터들이 생성된다. 그만큼 경기 결과에 영향을 미치는 변수들이 다수 존재한다. 통계의 스포츠라고 불리는 만큼 데이터가 중요한 야구에서는, 클래식 스탯, 세이버 메트릭스 등 다양한 통계 지표들이 있다. 그렇다면 야구 경기에서 승패 결과에 가장 큰 영향을 미치는 스탯은 무엇일까? 이 질문은 평소 야구를 좋아하면서 항상 궁금했던 점이기에, 단순 취미를 넘어서서 좀 더 다른 시각에서 야구 경기의 흐름을 바라보고 싶어 시작하게 된 분석이다. 그리고 분석 대상은, 2023 정규 시즌 LG 트윈스의 경기 기록이다.
왜 LG트윈스 경기를 분석했는가?
2023 KBO 리그의 우승팀은 정규 시즌 1위를 차지한 LG 트윈스이다. 29년만의 한국 시리즈 우승인 만큼 많은 팬들에게 감동을 안겨주었다. 2023 시즌 우승팀인 만큼 승리 요인을 분석해보는 것은 매우 의미있다고 보았으며, 정규 시즌 기록상 승리 횟수가 가장 많은 팀인 만큼 승리 요인의 분석이 가장 명확하게 진행될 것이라고 생각했다.
1. 데이터 수집
앞서 언급한 궁금증을 바탕으로 어떠한 데이터를 수집해야 할지 고민하는 과정에서 투수, 타자 각각에게서 가장 중요한 스탯이 무엇일지 생각해보았다. 그 결과, 투수들의 능력을 보여줄 수 있는 스탯은 ERA(평균 자책점), WHIP(이닝당 안타 및 볼넷 허용율)으로 선정했으며 타자들의 능력을 보여줄 수 있는 스탯은 OPS(출루율+장타율), AVG(타율)로 선정했다. 이 외에도 경기장의 분위기, 관중들의 응원 등의 요소를 고려해봤을때 홈, 어웨이 구장도 승패에 영향을 미칠 수 있다고 보았다.
결과적으로 수집해야 할 데이터셋의 형태는 아래와 같았다. 데이터의 출처는 스탯티즈이며, 2023 정규 시즌 LG 트윈스의 144경기 기록을 모두 수집하였다. ( *스탯티즈: 스포키 : STATIZ (sporki.com) ) 여기서 ERA, WHIP, OPS, AVG는 모두 그날 경기에 출전한 투수/타자 기록이 합산된 결과이다.
2-1. 데이터 분석
첫번째로, 구장별 승리 횟수를 살펴보았다. 데이터적으로 분석할만한 내용이 크지 않다고 보지만, 단순 궁금증으로 홈/어웨이 경기에서 경기장의 분위기가 다르기 때문에 이러한 요인이 승리에 영향을 미치는지 살펴보고 싶었다. LG 경기가 이루어진 구장 데이터에서 주목할 점은 LG와 두산이 잠실 야구장을 홈구장으로 함께 사용하고 있기 때문에 두산 vs LG 경기의 경우 잠실(홈) / 잠실(어웨이)로 저장했다는 것이다. 따라서 잠실, 잠실(홈)은 홈으로, 잠실(어웨이), 나머지 구장명은 어웨이로 다시 이름을 지정하였으며 코드는 아래와 같았다.
df.loc[df['stad'] == '잠실', 'stad'] = '홈'
df.loc[df['stad'] == '잠실(홈)', 'stad'] = '홈'
df.loc[df['stad'] != '홈', 'stad'] = '어웨이'
그리고 결과는 아래와 같았다. 역시나 데이터적으로 분석할만한 의미있는 결과는 아니기 때문에 홈 경기에서 승리 횟수가 더 많았다는 정도로만 해석했다.
2-2. 데이터 분석
본격적인 분석에 앞서 승리 요인을 분석하기 위해 필요한 도구가 무엇일지 생각해보았다. 이 분석에서 알아내고자 하는 것은, 예를 들어 OPS가 경기 결과에 얼만큼 영향을 미치는가이므로 상관 관계에 주목했다. 즉, 독립 변수는 앞선 데이터 셋에서 다양한 경기 데이터들이며, 종속변수는 승패인 것이다. 상관관계를 분석하기 위해서는 회귀 분석 모델이 필요했고, 머신러닝의 기초인 사이킷런 모델을 사용했다. 훈련 데이터와 테스트 데이터를 나누어 모델을 학습시킨 후 회귀 계수를 확인했다. 코드는 아래와 같다.
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 데이터 전처리(*승패 결과를 1과 0으로 변환)
X = df[['pit_ERA', 'pit_WHIP', 'hit_OPS', 'hit_AVG']]
y = df['w/l'].apply(lambda x: 1 if x == 'w' else 0)
# 훈련 데이터와 테스트 데이터로 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 선형 회귀 모델 초기화 및 훈련
model = LinearRegression()
model.fit(X_train, y_train)
# 훈련 및 테스트 데이터에 대한 예측
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
# 모델 평가 (평균제곱오차 계산)
train_mse = mean_squared_error(y_train, y_train_pred)
test_mse = mean_squared_error(y_test, y_test_pred)
print("훈련 데이터 MSE:", train_mse)
print("테스트 데이터 MSE:", test_mse)
# 회귀 계수 확인
coefficients = model.coef_
print("회귀 계수:", coefficients)
결과는 아래와 같다.
'pit_ERA', 'pit_WHIP', 'hit_OPS', 'hit_AVG' 각각의 회귀 계수는 -0.05843918 -0.21021701 0.94360031 0.40817375 이다. 여기서 회귀 계수는 각 독립 변수가 종속 변수에 미치는 영향의 크기이다. 'hit_OPS' 변수의 회귀 계수가 0.944 가장 크며 양의 값이므로, 'hit_OPS'가 승리에 가장 큰 영향을 준다고 볼 수 있다. 반면 'pit_WHIP' 변수의 회귀 계수는 -0.21로 음의 값이므로, 'pit_WHIP'가 승리에 부정적인 영향을 준다고 볼 수 있으며, 이는 WHIP 스탯이 의미하는 바를 고려했을 때 당연한 결과라고 볼 수 있다. 결과적으로 이 모델의 경우 OPS가 승패와 높은 상관관계(1.310)가 있다는 것을 확인할 수 있었다.
2-3. 데이터 분석
또 다른 선형 회귀 모델을 적용해보기로 했다. Ridge 모델을 적용했으며, 코드와 결과는 아래와 같다.
#Ridge 모델
from sklearn.linear_model import Ridge, Lasso
#데이터 전처리(*승패 결과를 1과 0으로 변환)
X = df[['pit_ERA', 'pit_WHIP', 'hit_OPS', 'hit_AVG']]
y = df['w/l'].apply(lambda x: 1 if x == 'w' else 0)
# 릿지 회귀 모델 초기화 및 훈련
ridge_model = Ridge(alpha=1.0) # alpha는 규제 강도를 조절하는 하이퍼파라미터
ridge_model.fit(X, y)
# 릿지 회귀 모델의 회귀 계수 확인
print("Ridge Regression Coefficients:", ridge_model.coef_)
2-2. 데이터 분석에서의 결과와 비슷하다. 역시나 OPS가 승패와 높은 상관관계(0.876)가 있다는 것을 확인할 수 있었다.
3. 분석의 확장
앞선 분석에서 생성한 모델을 바탕으로 다른 경기들의 데이터를 적용하여 모델의 예측도를 다시 한 번 검증해보았다. 검증 후에 예측도가 높다면, 이는 경기 데이터로 승리를 예측해볼 수 있다는 것을 의미하기 때문이다. 2-2. 데이터 분석, 2-3. 데이터 분석에서 생성한 2개의 모델에 각각 2024 LG 트윈스의 경기 결과를 입력했다. 아직 경기 데이터가 많지는 않으나, 2024년 3월 29일을 기준으로 존재하는 5개의 경기 데이터를 입력했다. 코드는 아래와 같다.
from sklearn.metrics import accuracy_score
#변수 선택
X_new = df2[['pit_ERA', 'pit_WHIP', 'hit_OPS', 'hit_AVG']]
#예측
y_pred = model.predict(X_new)
y_pred_label = ['w' if pred > 0.5 else 'l' for pred in y_pred]
#실제 승패 결과
y_true = df2['w/l']
#예측 정확도 계산
accuracy = accuracy_score(y_true, y_pred_label)
print("Accuracy:", accuracy)
from sklearn.metrics import accuracy_score
#변수 선택
X_new = df2[['pit_ERA', 'pit_WHIP', 'hit_OPS', 'hit_AVG']]
#예측
y_pred_ridge = ridge_model.predict(X_new)
y_pred_ridge_label = [1 if pred > 0.5 else 0 for pred in y_pred_ridge]
#실제 승패 결과
y_true = df2['w/l'].apply(lambda x: 1 if x == 'w' else 0)
#예측 정확도 계산
accuracy_ridge = accuracy_score(y_true, y_pred_ridge_label)
print("Ridge Regression Accuracy:", accuracy_ridge)
결과적으로 두 모델 모두 정확도는 0.8로, 높은 예측 정확도를 보였다.
두가지의 회귀 분석 모델을 활용한 결과, 승패에 가장 큰 영향을 미치는 것은 OPS이다. OPS는 타자의 공격력을 종합적으로 평가하는 지표이므로, 타자들이 출루하고 루를 돌면서 득점 기회를 창출하는 것이 승리에 중요한 역할을 한다는 당연하면서도 의미있는 결과이다. 또한 이를 바탕으로 생성한 모델을 통해 데이터로 승패 결과를 예측해볼 수 있다는 유의미한 결과를 보여준다.
이후 이 분석이 지닌 한계점 및 과정에 있어서 아쉬운 점에 대해서 생각해보았다.
첫번째로, 144경기의 기록을 모두 수집하는 과정에서 웹크롤링과 같은 도구를 사용했다면 데이터 수집 과정이 한층 더 수월했을 것이라고 생각한다. 데이터 수집 후 홈런 개수의 총합으로 올바르게 데이터를 수집 했는지 다시 한번 확인했지만, 다량의 경기 데이터를 수집해야 하는 경우 데이터 수집 과정이 비효율적이기 때문이다.
두번째로, 네가지 변수 외에도 다른 변수들과의 상관관계 또한 분석해보고 싶다는 아쉬움이 남았다. 하나의 경기에 수많은 데이터가 기록되고 이는 경기의 승패에 상당한 영향을 미치기 때문이다.
*코드: LG_Analysis.ipynb - Colaboratory (google.com)
데이터 분석-와인 데이터 최종 (0) | 2023.11.22 |
---|---|
2023 시즌 두산베어스 경기 데이터 분석 (0) | 2023.11.21 |
데이터 분석-K-Means, DBSCAN (0) | 2023.11.15 |
데이터 분석-PCA 분석 공부 (2) | 2023.11.08 |
데이터 분석-캐글 집값 예측(발표) (0) | 2023.09.29 |
댓글 영역