이번 포스트는 'R로 깔끔하게 머신러닝(랜덤 포레스트) 요리하기(feat. tidymodels)' 파이선 버전입니다.
똑같은 작업을 R로 할 때와 파이선으로 할 때 어떤 차이가 나는지 비교하려는 목적으로 이 포스트를 쓰고 있습니다.
그래서 그 포스트처럼 자세하게 설명하지는 않을 계획입니다.
랜덤 포레스트라는 모형이 무엇인지, 우리가 쓰는 데이터가 어떤 내용이 들어있는지 궁금하신 분은 'R로 깔끔하게 머신러닝(랜덤 포레스트) 요리하기(feat. tidymodels)' 포스트를 읽어 보시면 도움이 될 수 있습니다.
기본적으로 Sportugese에 '머신러닝으로 2019 사이영상 수상자 예상하기' 포스트를 쓰면서 했던 작업을 되살리는 게 이 포스트 목적입니다.
그래서 메이저리그 투수들 데이터를 가지고 랜덤 포레스트를 진행할 겁니다.
파이선도 코딩 첫 단계는 패키지 불러오기.
파이선에서 패지키는 PIP(Python Packages Index)를 통해 설치하는 게 기본입니다.
먼저 운영체제(OS) 쉘에서 (마이크로소프트·MS 윈도라면 커맨드 창)에서 다음 명령어로 이번 포스트에 필요한 패키지를 설치합니다.
pip install pandas
pip install numpy
pip install sklearn
pandas는 R에서 dplyr처럼 데이터 처리와 분석을 도와주는 패키지이고, numpy는 수치 계산을 도와주는 패키지입니다. sklearn(scikit-learn)은 머신러닝 패키지입니다.
패키지 설치를 끝내셨다면 이제 본격적으로 코딩에 들어갑니다.
일단 pandas와 numpy부터 불러옵니다.
import pandas as pd
import numpy as np
이어서 데이터를 읽어들입니다. 우리가 쓸 파일은 2009년이후 11년 동안 메이저리그에서 규정 이닝을 채운 투수들 각종 기록 순위 파일입니다.
아래 명령어로 CSV(Comma-Seperated Values) 파일을 불러올 수 있습니다.
cya = pd.read_csv('cya.csv')
이 파일 맨 첫 여섯 번째 줄만 열어 보면 이렇게 생겼습니다.
print(cya.head(6))
season name team lg cy ... hr k9 bb9 kbb babip 0 2019 Gerrit Cole Astros AL X ... 13 1 4 2 4 1 2019 Lance Lynn Rangers AL X ... 5 7 11 6 21 2 2019 Justin Verlander Astros AL X ... 21 2 2 1 1 3 2019 Charlie Morton Rays AL X ... 1 5 13 5 12 4 2019 Shane Bieber Indians AL X ... 17 6 1 3 11 5 2019 Lucas Giolito White Sox AL X ... 9 3 14 7 3
그리고 'R로 깔끔하게 머신러닝(랜덤 포레스트) 요리하기(feat. tidymodels)'에서 했던 것처럼 (당시까지) 결과를 알 수 없던 2019년 자료를 별도로 분리합니다.
cya_2019 = cya.query('season==2019')
그리고 나머지 데이터도 cya_pre라는 변수에 따로 뽑습니다.
cya_pre = cya.query('season!=2019')
우리는 여러 야구 기록 순위를 토태로 사이영상 투표 점수를 예측하려고 합니다.
여러 기록 순위는 일곱 번째 열부터 들어 있습니다. 파이선은 0부터 숫자를 세니까 6을 기준으로 하면 됩니다.
x = cya_pre.iloc[:, 6:].values
우리가 예상하려는 값은 'vote'라는 열에 들어 있습니다.
y = cya_pre['vote'].values
어떻게 생겼는지 궁금하니까 한번 x, y를 출력해 보겠습니다.
print(x)
[[12 13 9 ... 4 5 26] [23 25 25 ... 15 16 25] [ 4 14 6 ... 6 3 24] ... [15 10 21 ... 29 20 3] [20 17 15 ... 5 4 2] [27 7 27 ... 12 18 1]]
print(y)
[ 0 0 0 1 0 0 0 13 0 0 26 0 0 0 0 71 0 154 0 0 0 0 0 0 0 169 0 0 0 0 23 0 0 0 2 0 0 0 49 0 0 207 0 0 13 0 0 0 0 123 0 86 3 0 0 0 0 0 0 0 0 2 0 0 43 0 126 0 0 0 0 0 73 32 0 204 0 3 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 52 0 0 0 81 0 0 126 6 18 0 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 40 0 0 6 98 0 137 0 14 6 0 132 0 0 15 18 0 0 0 0 0 0 0 0 0 19 0 0 0 0 0 0 1 0 46 0 102 0 192 0 85 2 0 0 0 0 30 0 5 0 0 0 0 2 0 0 4 29 0 0 0 143 0 0 0 9 0 0 0 0 0 0 0 0 186 0 82 0 3 0 0 0 0 0 0 0 0 0 0 0 40 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 8 101 0 0 7 32 0 0 169 147 0 6 0 0 169 0 32 0 16 0 46 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 0 0 0 0 0 0 0 159 0 0 0 0 0 0 3 0 6 0 1 0 0 25 0 0 0 28 0 0 17 0 0 0 0 0 0 0 0 210 0 0 0 0 0 97 0 0 0 0 0 5 0 112 0 0 0 0 0 6 0 0 0 0 46 4 0 0 0 0 0 0 2 0 0 25 0 44 0 0 0 0 0 0 0 93 0 0 203 73 0 0 0 0 0 0 86 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 0 39 0 0 0 19 0 21 0 0 0 0 207 3 0 62 0 0 0 0 0 0 0 0 0 0 41 0 0 0 1 17 0 0 0 0 0 0 0 159 2 0 0 0 0 149 0 0 0 0 70 0 0 0 0 0 0 0 0 0 0 0 0 0 75 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 209 0 0 0 0 0 0 93 0 0 6 96 22 0 63 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 66 0 0 97 3 2 196 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 0 0 0 0 90 0 5 0 0 0 0 0 0 7 1 0 0 0 0 0 0 0 76 207 0 0 0 0 0 3 17 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 0 0 6 0 1 0 0 102 0 24 0 0 0 0 0 0 0 0 111 0 167 0 20 0 4 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 34 0 0 0 224 0 0 2 0 0 0 0 0 0 0 0 122 0 0 4 0 90 0 0 14 1 0 39 0 1 0 0 14 0 0 0 11 134 0 0 0 0 0 0 0 0 0 0 80 0 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 0 0 0 0 0 0 0 0 0 0 0 0 0 3 100 0 0 0 0 0 94 0 0 1 0 0 0 0 0 0]
머신러닝을 진행할 때는 데이터를 학습용(또는 훈련용)과 시험용(또는 검증용)으로 나눠야 합니다.
파이선에서는 train_test_split() 함수를 써서 이 작업을 진행할 수 있습니다.
먼저 sklearn 패키지에서 이 함수를 불러옵니다.
from sklearn.model_selection import train_test_split
그리고 30%를 시험용 데이터에 할당하는 코드를 씁니다.
cya_pre_train, cya_pre_test, vote_train, vote_test = train_test_split(x, y, test_size=0.3, random_state=777)
머신러닝 작업에는 데이터를 척도화하는 절차가 필요합니다.
파이선에서 이 작업을 담당하는 StandardScaler를 불러옵니다.
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
학습용 데이터는 모델 적용 과정을 거쳐 척도화 해야 하니까 sc.fit_transform() 함수를 씁니다.
cya_pre_train = sc.fit_transform(cya_pre_train)
print 해서 결과 확인.
print(cya_pre_train)
[[-0.63687549 -0.67524191 -0.05789852 ... -1.51907634 -1.51223654 -0.596801 ] [ 0.69889333 0.74577531 -0.72412806 ... 0.56953428 -0.15914888 0.83542512] [ 1.78420549 1.91602479 0.7748884 ... 0.9872564 1.19393878 1.84640826] ... [ 1.03283553 1.5816678 -1.05724283 ... -0.85072094 -1.00482867 1.00392231] [-0.46990439 -1.1767774 1.35783925 ... 1.40497853 1.36307473 -0.34405522] [-1.55521655 -1.59472364 -1.14052152 ... -1.51907634 -1.59680452 -1.27078976]]
시험용 데이터는 transform()이면 충분합니다.
cya_pre_test = sc.transform(cya_pre_test)
마찬가지로 출력.
print(cya_pre_test)
[[-0.38641884 0.24423982 -0.47429198 ... -0.18236554 -0.4974208 -0.42830381] [-1.13778879 -1.0095989 -0.80740675 ... -0.34945439 -1.00482867 0.24568495] [ 0.28146557 -1.51113439 0.44177363 ... -0.60008767 -0.24371686 -1.10229257] ... [ 1.11632108 -0.25729567 0.27521625 ... -0.09882112 -0.41285282 -0.76529819] [-1.05430324 0.57859682 -1.3903576 ... -1.51907634 -1.59680452 -1.27078976] [-0.38641884 -0.17370642 1.52439664 ... 1.57206738 1.53221069 -1.43928695]]
이제 데이터 정리가 끝났으니가 회귀(regression) 모드로 랜덤 포레스트를 진행할 수 있도록 RandomForestRegressor를 불러옵니다.
from sklearn.ensemble import RandomForestRegressor
다음 단계는 모델 만들기.
model = RandomForestRegressor(n_estimators=100, random_state=777)
이 모델은 이렇게 생겼습니다.
print(model)
RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mse', max_depth=None, max_features='auto', max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=None, oob_score=False, random_state=777, verbose=0, warm_start=False)
학습용 데이터로 공부를 시킵니다.
model.fit(cya_pre_train, vote_train)
그리고 시험용 데이터를 가지고 결과를 예상해 보도록 합니다.
vote_pred = model.predict(cya_pre_test)
이런 결과가 나옵니다.
print(vote_pred)
[0.0000e+00 4.0000e-02 4.5000e-01 9.3000e+00 9.0000e-02 0.0000e+00 1.0988e+02 0.0000e+00 4.2420e+01 2.3200e+01 0.0000e+00 0.0000e+00 0.0000e+00 1.5399e+02 1.6440e+01 1.0000e-01 0.0000e+00 0.0000e+00 0.0000e+00 2.0000e-02 0.0000e+00 9.1300e+00 0.0000e+00 1.2239e+02 5.9520e+01 2.0000e-01 0.0000e+00 0.0000e+00 0.0000e+00 2.5270e+01 1.0000e-02 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 2.0000e-02 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 2.8000e-01 0.0000e+00 0.0000e+00 2.0000e-02 0.0000e+00 0.0000e+00 1.0000e-02 0.0000e+00 1.3190e+01 0.0000e+00 1.3000e-01 4.1600e+01 0.0000e+00 0.0000e+00 6.9800e+00 0.0000e+00 1.4430e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 1.4251e+02 1.2000e-01 1.2220e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 5.3000e-01 0.0000e+00 1.9520e+01 0.0000e+00 1.6580e+01 8.1000e-01 0.0000e+00 0.0000e+00 0.0000e+00 1.0000e-02 4.2900e+01 1.3200e+02 4.9800e+00 0.0000e+00 0.0000e+00 0.0000e+00 5.0000e-02 0.0000e+00 5.5000e-01 0.0000e+00 1.2930e+01 0.0000e+00 1.2966e+02 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 7.0000e-02 0.0000e+00 8.0000e-02 0.0000e+00 0.0000e+00 0.0000e+00 3.2040e+01 9.7000e+00 2.5420e+01 5.5000e-01 0.0000e+00 0.0000e+00 1.5074e+02 1.5000e-01 0.0000e+00 1.3686e+02 0.0000e+00 0.0000e+00 3.1900e+00 5.9200e+00 0.0000e+00 0.0000e+00 0.0000e+00 6.7900e+00 1.7400e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 4.6000e-01 0.0000e+00 0.0000e+00 0.0000e+00 5.9000e+00 1.7900e+01 0.0000e+00 1.6500e+00 0.0000e+00 0.0000e+00 1.7120e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 8.2000e+00 4.4200e+00 0.0000e+00 7.0260e+01 1.3260e+01 2.4000e-01 0.0000e+00 1.6600e+00 2.8700e+00 1.4957e+02 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 2.1000e-01 0.0000e+00 0.0000e+00 3.4700e+01 0.0000e+00 1.4320e+01 0.0000e+00 0.0000e+00 1.2668e+02 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 2.0000e-02 0.0000e+00 0.0000e+00 0.0000e+00 2.9400e+00 0.0000e+00 0.0000e+00 0.0000e+00 1.9250e+01 7.8860e+01 0.0000e+00 0.0000e+00 1.0880e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 5.0000e-02 0.0000e+00 3.7800e+00 0.0000e+00 1.3470e+01 2.8000e-01 2.8900e+00 8.2000e-01 0.0000e+00 0.0000e+00 2.2000e-01 2.0000e-02 0.0000e+00 6.4360e+01 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 1.9820e+01 0.0000e+00 1.0000e-02 1.1350e+01 0.0000e+00 5.1000e-01 2.5340e+01 0.0000e+00]
모델은 만들었으니까 성능도 측정해 봐야겠죠?
이를 도와주는 metrics를 불러옵니다.
from sklearn import metrics
이어서 평균 제곱근 편차(RMSE), 결정계수(R²), 오차 절대값 평균(MAE)을 출력하도록 합니다.
print("1. rmse:", np.sqrt(metrics.mean_squared_error(vote_test, vote_pred)))
print("2. rsq:", (metrics.r2_score(vote_test, vote_pred)))
print("3. mae:", metrics.mean_absolute_error(vote_test, vote_pred))
1. rmse: 13.43795868531819 2. rsq: 0.8374295843402872 3. mae: 4.796991150442477
R로 만든 모형이 R² .798이었으니까 파이선(.837) 쪽이 분산을 더 잘 설명한다고 할 수 있습니다.
이제 2018년 이전 전체 데이터에 모형을 적용해 봅니다.
model.fit(x, y)
마찬가지로 투표 결과를 예상해 보라고 주문합니다.
vote_pred2 = model.predict(x)
위에서 보신 것처럼 이 예상 결과는 데이터 프레임 형태가 아닙니다. 그래서 그렇게 바꿉니다.
pred2_pd = pd.DataFrame(vote_pred2, columns=['pred'])
pred 0 0.00 1 0.00 2 8.39 3 5.87 4 0.00 .. ... 746 0.01 747 0.00 748 0.64 749 0.08 750 0.00 [751 rows x 1 columns]
예상 결과만 덜렁 있으니 어떤 선수를 예상했는지 알기 어렵습니다.
pd.concat() 함수를 써서 원래 데이터와 예상 결과를 합칩니다.
cya_pre는 원래 데이터에서 아랫 부분을 잘라낸 형태라 인덱스가 0부터 시작하지 않습니다.
그래서 reset_index() 함수로 인덱스를 초기화하는 작업도 함께 진행합니다.
axis=1은 옆으로 붙이라는 뜻입니다. 아래로 붙일 때는 axis=0.
result = pd.concat([cya_pre.reset_index(drop=True), pred2_pd], axis=1)
역시 출력을 해봅니다.
print(result)
season name team lg cy ... k9 bb9 kbb babip pred 0 2018 Marco Gonzales Mariners AL X ... 20 4 5 26 0.00 1 2018 Dylan Bundy Orioles AL X ... 9 15 16 25 0.00 2 2018 Carlos Carrasco Indians AL X ... 5 6 3 24 8.39 3 2018 Luis Severino Yankees AL X ... 7 7 4 23 5.87 4 2018 Mike Leake Mariners AL X ... 26 3 14 22 0.00 .. ... ... ... .. .. ... .. ... ... ... ... 746 2009 Bronson Arroyo Reds NL X ... 37 17 35 5 0.01 747 2009 Ross Ohlendorf Pirates NL X ... 34 19 30 4 0.00 748 2009 Matt Cain Giants NL X ... 23 29 20 3 0.64 749 2009 Ted Lilly Cubs NL X ... 20 5 4 2 0.08 750 2009 Randy Wolf Dodgers NL X ... 28 12 18 1 0.00 [751 rows x 20 columns]
사실 우리는 진짜 투표 결과를 정확하게 예상하고 싶었던 건 아닙니다.
예상 점수 1등이 사이영상을 탔는지 아닌지 알고 싶은 것.
이를 알아보려면 먼저 각 시즌별 리그 예상 점수 순위를 더해줘야 합니다.
result['rank'] = result.groupby(['season', 'lg'])['pred'].rank(ascending=False)
그다음 실제로 사이영상을 탄 사람 그러니까 cy열이 'O'인 열 또는(or) 예상 점수가 1등인 선수만 골라냅니다.
print(result.query("cy=='O' | rank==1"))
season name team lg cy ... bb9 kbb babip pred rank 735 2009 Tim Lincecum Giants NL O ... 20 7 16 112.80 1.0 683 2009 Zack Greinke Royals AL O ... 5 2 23 143.04 1.0 650 2010 Roy Halladay Phillies NL O ... 1 1 25 193.12 1.0 626 2010 Felix Hernandez Mariners AL O ... 13 7 4 148.43 1.0 580 2011 Clayton Kershaw Dodgers NL O ... 12 3 6 189.34 1.0 536 2011 Justin Verlander Tigers AL O ... 8 3 2 184.80 1.0 482 2012 R.A. Dickey Mets NL O ... 11 3 14 181.71 1.0 443 2012 Justin Verlander Tigers AL X ... 12 3 7 151.15 1.0 437 2012 David Price Rays AL O ... 17 11 13 144.07 2.0 410 2013 Clayton Kershaw Dodgers NL O ... 9 5 3 187.41 1.0 368 2013 Max Scherzer Tigers AL O ... 14 5 3 175.68 1.0 319 2014 Clayton Kershaw Dodgers NL O ... 4 1 15 181.00 1.0 256 2014 Corey Kluber Indians AL O ... 9 6 34 169.00 1.0 250 2015 Jake Arrieta Cubs NL O ... 10 8 2 163.77 1.0 209 2015 Dallas Keuchel Astros AL O ... 8 5 5 162.73 1.0 173 2016 Max Scherzer Nationals NL O ... 11 1 4 163.65 1.0 146 2016 Justin Verlander Tigers AL X ... 11 7 2 142.45 1.0 141 2016 Rick Porcello Red Sox AL O ... 2 2 7 129.96 2.0 107 2017 Max Scherzer Nationals NL O ... 9 3 2 185.28 1.0 75 2017 Corey Kluber Indians AL O ... 1 1 3 187.17 1.0 41 2018 Jacob deGrom Mets NL O ... 3 2 12 169.83 1.0 25 2018 Blake Snell Rays AL O ... 20 15 1 154.05 1.0 [22 rows x 21 columns]
보시면 2012년과 2016년 아메리칸리그 사이영상 수상자와 예상 점수 1등 선수가 다르다는 사실을 알 수 있습니다.
공교롭게도 두 번 모두 저스틴 벌랜더가 예상 점수는 제일 높았는데 사이영상은 다른 선수에게 돌아갔습니다.
이제 이 모형을 2019년 자료에 적용합니다. 위에서 쓴 코드를 그냥 Ctrl+C/V하면 됩니다.
x_2019 = cya_2019.iloc[:, 6:].values
vote_pred3 = model.predict(x_2019)
pred3_pd = pd.DataFrame(vote_pred3, columns=['pred'])
result = pd.concat([cya_2019.reset_index(drop=True), pred3_pd], axis=1)
result['rank'] = result.groupby('lg')['pred'].rank(ascending=False)
각 리그별 예상 순위를 정렬하면 되겠죠?
print(result.sort_values(by=['lg', 'pred'], ascending=False))
season name team lg ... kbb babip pred rank 22 2019 Jacob deGrom Mets NL ... 3 16 145.15 1.0 24 2019 Stephen Strasburg Nationals NL ... 9 12 129.81 2.0 26 2019 Hyun-Jin Ryu Dodgers NL ... 2 14 50.11 3.0 34 2019 Mike Soroka Braves NL ... 17 15 30.83 4.0 23 2019 Max Scherzer Nationals NL ... 1 31 26.39 5.0 41 2019 Max Fried Braves NL ... 16 33 16.32 6.0 27 2019 Patrick Corbin Nationals NL ... 19 19 14.53 7.0 28 2019 Jack Flaherty Cardinals NL ... 11 2 10.81 8.0 25 2019 Walker Buehler Dodgers NL ... 4 19 10.39 9.0 38 2019 Clayton Kershaw Dodgers NL ... 8 4 8.87 10.0 31 2019 Sonny Gray Reds NL ... 22 3 3.75 11.0 55 2019 Dakota Hudson Cardinals NL ... 34 12 2.28 12.0 33 2019 Luis Castillo Reds NL ... 24 4 1.61 13.0 29 2019 Zack Wheeler Mets NL ... 15 28 1.07 14.0 47 2019 Robbie Ray Diamondbacks NL ... 27 27 0.05 15.5 49 2019 Adam Wainwright Cardinals NL ... 30 30 0.05 15.5 54 2019 Jeff Samardzija Giants NL ... 25 1 0.01 17.0 30 2019 Noah Syndergaard Mets NL ... 13 29 0.00 26.0 32 2019 Kyle Hendricks Cubs NL ... 7 17 0.00 26.0 35 2019 Jose Quintana Cubs NL ... 20 32 0.00 26.0 36 2019 Aaron Nola Phillies NL ... 23 23 0.00 26.0 37 2019 German Marquez Rockies NL ... 5 26 0.00 26.0 39 2019 Joe Musgrove Pirates NL ... 14 24 0.00 26.0 40 2019 Madison Bumgarner Giants NL ... 6 18 0.00 26.0 42 2019 Jon Lester Cubs NL ... 21 34 0.00 26.0 43 2019 Yu Darvish Cubs NL ... 12 7 0.00 26.0 44 2019 Miles Mikolas Cardinals NL ... 10 25 0.00 26.0 45 2019 Anibal Sanchez Nationals NL ... 31 6 0.00 26.0 46 2019 Anthony DeSclafani Reds NL ... 18 11 0.00 26.0 48 2019 Sandy Alcantara Marlins NL ... 33 9 0.00 26.0 50 2019 Joey Lucchesi Padres NL ... 26 9 0.00 26.0 51 2019 Merrill Kelly Diamondbacks NL ... 28 22 0.00 26.0 52 2019 Julio Teheran Braves NL ... 32 7 0.00 26.0 53 2019 Zach Eflin Phillies NL ... 29 21 0.00 26.0 0 2019 Gerrit Cole Astros AL ... 2 4 157.77 1.0 2 2019 Justin Verlander Astros AL ... 1 1 153.78 2.0 3 2019 Charlie Morton Rays AL ... 5 12 74.07 3.0 4 2019 Shane Bieber Indians AL ... 3 11 37.26 4.0 1 2019 Lance Lynn Rangers AL ... 6 21 26.18 5.0 5 2019 Lucas Giolito White Sox AL ... 7 3 16.20 6.0 6 2019 Jose Berrios Twins AL ... 8 13 6.22 7.0 8 2019 Eduardo Rodriguez Red Sox AL ... 12 19 5.62 8.0 7 2019 Mike Minor Rangers AL ... 11 7 3.67 9.0 9 2019 Marco Gonzales Mariners AL ... 15 10 2.32 10.0 20 2019 Mike Fiers Athletics AL ... 18 2 0.95 11.0 10 2019 Matthew Boyd Tigers AL ... 4 15 0.32 12.0 17 2019 Wade Miley Astros AL ... 19 7 0.02 13.0 11 2019 Masahiro Tanaka Yankees AL ... 9 9 0.00 18.0 12 2019 Homer Bailey - - - AL ... 14 14 0.00 18.0 13 2019 Reynaldo Lopez White Sox AL ... 16 17 0.00 18.0 14 2019 Brad Keller Royals AL ... 22 6 0.00 18.0 15 2019 Ivan Nova White Sox AL ... 17 21 0.00 18.0 16 2019 Brett Anderson Athletics AL ... 21 5 0.00 18.0 18 2019 Martin Perez Twins AL ... 20 17 0.00 18.0 19 2019 Rick Porcello Red Sox AL ... 10 16 0.00 18.0 21 2019 Jakob Junis Royals AL ... 13 20 0.00 18.0 [56 rows x 21 columns]
내셔널리그에서는 제이컵 디그롬, 아메리칸리그에서는 게릿 콜이 제일 높은 예상 점수를 받았습니다.
실제로는 내셔널리그 사이영상은 디그롬이 받았지만 아메리칸리그에서는 콜이 받지 못했습니다. 지난해 아메리칸리그 사이영상 수상자는 벌랜더였습니다.
어쩌면 이 모형은 벌랜더와 엇갈리는 운명인지도 모를 일입니다.
어떠신가요? 여러분은 R이 더 편하십니까? 아니면 파이선이 더 훌륭합니까?
댓글,