[MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 2. Modeling & Prediction

2021. 7. 28. 13:45·Minding's Baseball/머신러닝으로 홈런왕 예측하기
728x90
반응형

작성 코드 및 데이터 (Github, Predict_HR폴더) :

https://github.com/JeongMinHyeok/Handling_MLB_Statcast

 

GitHub - JeongMinHyeok/Handling_MLB_Statcast

Contribute to JeongMinHyeok/Handling_MLB_Statcast development by creating an account on GitHub.

github.com

 

EDA & Data Engineering [이전포스팅]

 

2021.07.27 - [Handling MLB StatCast] - [MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 1. EDA & Data Engineering

 

[MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 1. EDA & Data Engineering

머신러닝 코드 및 데이터자료 (아래 링크의 Predict_HR 폴더) https://github.com/JeongMinHyeok/Handling_MLB_Statcast GitHub - JeongMinHyeok/Handling_MLB_Statcast Contribute to JeongMinHyeok/Handling_MLB..

minding-deep-learning.tistory.com

 


사용할 학습 모델은 Lasso, ElasticNet, RandomForest, GradientBoosting, XGBoost, LightGBM 중

KFold를 통해 오차를 검정하여 3개의 모델을 선정하고,

앙상블 / 보팅 / 스태킹을 사용하여 예측을 진행할 계획을 설정하고 진행했다.

 

RobustScaler

  • 학습을 진행하기 전에, 중앙값과 IQR을 사용한 RobustScaler를 통해 아웃라이어의 영향을 최소화했다.
from sklearn.preprocessing import RobustScaler

rbst_scaler=RobustScaler()
X_rbst=rbst_scaler.fit_transform(x_train)
test_rbst=rbst_scaler.transform(x_test)

 

KFold 검정

kfold = KFold(n_splits=4)

random_state = 1
reg = []

reg.append(Lasso(random_state = random_state))
reg.append(ElasticNet(random_state = random_state))
reg.append(RandomForestRegressor(random_state=random_state))
reg.append(GradientBoostingRegressor(random_state=random_state))
reg.append(XGBRegressor(silent=True,random_state=random_state))
reg.append(LGBMRegressor(verbose_eval=False,random_state = random_state))

# print(reg)

reg_results = []

for regre in reg :
    reg_results.append(np.mean(np.sqrt(-cross_val_score(regre, X_rbst, y = y_data ,scoring = 'neg_mean_squared_error',
                                       cv = kfold, n_jobs=-4))))

# Kfold 검정결과 저장
reg_means = []
reg_std = []
for reg_result in reg_results:
    reg_means.append(reg_result.mean())
    reg_std.append(reg_result.std())
    
    
# 위에서부터 Lasso, ElasticNet, RandomForest, GradientBoosting, XGBoost, LGBM에 대한 교차검증결과
# 평균이 낮을수록 좋음

reg_re = pd.DataFrame({"CrossValMeans":reg_means,"CrossValerrors": reg_std})
reg_re

위에서부터 Lasso, ElasticNet, RandomForest, GradientBoosting, XGBoost, LGBM에 대한 교차검증결과

  • CrossValMeans 확인 : GradeintBoosting, RandomForest, LightGBM 모델에 대해 파라미터 튜닝 결정

GridSearchCV로 모델 파라미터 튜닝

# Gradient boosting 파라미터 튜닝
GBC = GradientBoostingRegressor()
gb_param_grid = {'n_estimators' : [30,50,100],
              'learning_rate': [0.1, 0.01, 0.2],
              'max_depth': [3, 4, 5],
              'min_samples_leaf': [20,30,40],
              'max_features': [0.3, 0.2, 0.15] 
              }
gsGBC = GridSearchCV(GBC,param_grid = gb_param_grid, cv=kfold, scoring="neg_mean_squared_error", n_jobs= 4, verbose = 1)
gsGBC.fit(X_rbst,y_data)
GBC_best = gsGBC.best_estimator_

# 최고 점수
gsGBC.best_score_

>>>
-0.05544372851288073
# RandomForest 파라미터 튜닝
RF = RandomForestRegressor()
rf_param_grid = {'n_estimators' : [10, 20, 30],
              'max_depth': [6, 8, 10, 12, 15],
              'min_samples_leaf': [5, 10, 20, 30],
              'max_features': [0.4, 0.6, 0.8, 1] 
              }
gsRF = GridSearchCV(RF,param_grid = rf_param_grid, cv=kfold, scoring="neg_mean_squared_error", n_jobs= 4, verbose = 1)
gsRF.fit(X_rbst,y_data)
RF_best = gsRF.best_estimator_

# 최고 점수
gsRF.best_score_

>>>
-0.05524458001657022
#LGBMClassifier 파라미터 튜닝
LGB = LGBMRegressor()
lgb_param_grid = {
    'n_estimators' : [30, 50, 70],
    'learning_rate': [0.1],
    'max_depth': [5, 10, 15],
    'num_leaves': [10, 30, 50],
    'min_split_gain': [0.1, 0.2, 0.3],
}
gsLGB = GridSearchCV(LGB,param_grid = lgb_param_grid, cv=kfold, scoring="neg_mean_squared_error", n_jobs= 4, verbose = 1)
gsLGB.fit(X_rbst,y_data)
LGB_best = gsLGB.best_estimator_

# 최고 점수
gsLGB.best_score_

>>>
-0.05724827980153845

 

예측

  • 앙상블
test_Survived_GBC = pd.Series(GBC_best.predict(test_rbst), name="GBC")
test_Survived_RF = pd.Series(RF_best.predict(test_rbst), name="RF")
test_Survived_LGB = pd.Series(LGB_best.predict(test_rbst), name="LGB")

ensemble_results = pd.concat([test_Survived_RF,test_Survived_LGB,
                              test_Survived_GBC],axis=1)
g= sns.heatmap(ensemble_results.corr(),annot=True)

ensemble = np.expm1(0.1*test_Survived_GBC + 0.8*test_Survived_RF + 0.1*test_Survived_LGB)
prediction = pd.DataFrame({
    "player_id" :player_id,
    "name" : name,
    "HR": ensemble
})

 

  • 보팅 (Voting)
from sklearn.ensemble import VotingRegressor

votingC = VotingRegressor(estimators=[('RF', RF_best), ('LGB', LGB_best), ('GBC',GBC_best)], n_jobs=4)
votingC = votingC.fit(X_rbst, y_data)

test_HR = pd.Series(votingC.predict(test_rbst), name="HR")

predict_voting = pd.DataFrame({
    "player_id" :player_id,
    "name" : name,
    "HR": np.expm1(test_HR)
})

 

  • 스태킹(stacking)
from mlxtend.regressor import StackingRegressor
from sklearn.linear_model import LogisticRegression
from sklearn.utils.testing import ignore_warnings

params = {'meta_regressor__C': [0.1, 1.0, 10.0, 100.0],
          'use_features_in_secondary' : [True, False]}
clf1 = RF_best
clf2 = LGB_best
clf3 = GBC_best

lr = LogisticRegression()
st_re= StackingRegressor(regressors=[clf1, clf2, clf3], meta_regressor=RandomForestRegressor())
st_mod = st_re.fit(X_rbst, y_data)
st_pred = st_mod.predict(test_rbst)
predict_stacking = pd.DataFrame({
    "player_id" :player_id,
    "name" : name,
    "HR": np.expm1(st_pred)
})

 

예측결과

  • [이름 / 예측홈런갯수 / 연도 / 실제시즌 홈런갯수(7/28일 기준)]
  • 앙상블 (Ensemble)

 

  • 보팅 (Voting)

 

  • 스태킹 (Stacking)

 


생각치도 못한 결과다...

앙상블, 보팅, 스태킹 중 두 모델이 보스턴 레드삭스의 라파엘 데버스 선수가 홈런왕에 오를거라는 예측을 내놓았다.

홈런갯수는 아직 데이터 전처리가 부족했다고 쳐도, 홈런 순위는 비슷할거라 생각했는데 큰 오산이었다.

 

물론, 라파엘 데버스 선수도 파워를 강점으로 가지고 있는 강타자이다.

하지만 현재 홈런 1위를 달리고 있는 오타니가 35개로 10개 가까이 차이나는 것을 보면, 결과가 조금 이상하다고 볼 수 있다.

 

홈런갯수와 관련된 것은, 아마 홈런타자들을 제외한 다른 타자들의 영향이 컸을거라고 생각한다.

그래서, 다음번엔 홈런타자들 위주로 데이터를 구성하여 예측을 해 볼 예정이다.

 

그리고 현재 오타니처럼 홈런왕 경쟁에서 단독으로 치고나갈 경우, 예측이 어려울 수 있다는 것을 배웠다.

머신러닝 데이터는 일반적으로 평균에 가깝게 구성을 하기 때문에, 오타니와 같은 데이터는 이상치라고 생각할 수 있을 것이다.

다음 프로젝트에는 이 또한 정확하게 예측할 수 있도록 방법을 강구해보아야 할 것이다.

728x90

'Minding's Baseball > 머신러닝으로 홈런왕 예측하기' 카테고리의 다른 글

[MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 3. 데이터 재전처리하여 예측  (0) 2021.08.03
[MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 1. EDA & Data Engineering  (5) 2021.07.27
'Minding's Baseball/머신러닝으로 홈런왕 예측하기' 카테고리의 다른 글
  • [MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 3. 데이터 재전처리하여 예측
  • [MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 1. EDA & Data Engineering
Minding
Minding
  • Minding
    Today's Minding
    Minding
  • 전체
    오늘
    어제
    • 울고넘는 딥러닝 (278)
      • Minding's Baseball (57)
        • MLB Statcast (29)
        • 머신러닝으로 홈런왕 예측하기 (3)
        • 야구칼럼 (12)
        • 야구 규칙, 용어 (1)
        • 2022-23 질롱 코리아 (8)
        • 류현진 등판경기 (4)
      • Minding's Programming (185)
        • 프로그래머스 코딩테스트 (21)
        • Knowledge (44)
        • Numpy & Pandas (6)
        • Excel (3)
        • Git (1)
        • Pygame (11)
        • CV (3)
        • Tensorflow tutorial (4)
        • Kaggle and Dacon (4)
        • 에러 코드 (8)
        • FastAPI (8)
        • Airflow (29)
        • Crawling (6)
        • Django (14)
        • AWS (18)
        • Spark (5)
      • Minding's Reading (30)
        • 머신러닝 딥러닝에 필요한 기초 수학 with 파이.. (2)
        • 칼만필터는 어렵지 않아 (11)
        • 밑바닥부터 시작하는 딥러닝 (6)
        • 메이저리그 야구 통계학 2e (8)
        • 논문읽기 (2)
        • 빅데이터를 지탱하는 기술 (1)
      • Minding's Life (5)
        • 주식 (4)
        • 각종 소식 (1)
  • 블로그 메뉴

    • 홈
    • Baseball
    • Programming
    • Reading
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    데이터분석
    메이저리그
    질롱코리아
    Airflow
    칼만필터
    AWS
    파이썬
    FastAPI
    데이터 엔지니어
    django python
    칼만필터는어렵지않아
    딥러닝
    에어플로우
    django
    KBO
    코딩테스트
    MLB
    파이게임
    넘파이
    프로그래머스
    게임개발
    칼만필터는어렵지않아파이썬
    KalmanFilter
    pygame
    Python
    머신러닝
    칼만필터는어렵지않아python
    mlb stats api
    야구
    파이썬게임개발
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Minding
[MLB 스탯캐스트] 머신러닝으로 MLB 타자들의 최종 홈런 성적 예측해보기 - 2. Modeling & Prediction
상단으로

티스토리툴바