聰明不如鈍筆
총명불여둔필
assignment Kidult

파이선으로 머신러닝(랜덤 포레스트) 돌려보기


이번 포스트는 '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년 동안 메이저리그에서 규정 이닝을 채운 투수들 각종 기록 순위 파일입니다.


cya.csv


아래 명령어로 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이 더 편하십니까? 아니면 파이선이 더 훌륭합니까?

댓글,

Kidult | 카테고리 다른 글 더 보기