2,937 views
この記事は最終更新から 1812日 が経過しています。
姉妹サイト Octaveやってみる! で2014年に遊んでみた (32) 野球選手の成績を主成分分析 と同じことを Pythonでもやってみる。
対象データは 2016年のプロ野球セパ両リーグのレギュラークラス 55人の打者成績とする。
データはYahoo!さんのサイト(↑)からお借りしました。m(_ _)m
1. テーマは野球選手の総合評価
個人的には、何でもそつなくこなす選手が好きです。
蓑田選手(阪急)
松永選手(阪急)
前田選手(広島)
などなど、本塁打、打点、打率などの単一項目での評価ではなく、
タイトルホルダーじゃないけどスゴイ選手!
の度合が計測できる、そんな物差しを見つけてくれることを楽しみにやってみます。
2. 計算手順
主成分分析の対象とする変量(打者成績項目)は、以下の9項目とする。
打席数、安打、本塁打、塁打数、打点、得点、三振、四球、盗塁
前述の打者成績をCSVファイルに保存しておき、これをPythonでロードする。
※今回はscikit-learnを使わずにPCAしてみる。
>>> import numpy as np >>> X = np.loadtxt('in_data.csv', delimiter=',') >>> X array([[ 576., 168., 23., 271., 75., 96., 67., 81., 13.], [ 528., 156., 29., 285., 95., 76., 79., 53., 16.], [ 561., 151., 44., 319., 110., 89., 105., 87., 0.], [ 640., 181., 13., 248., 56., 92., 106., 40., 13.], [ 523., 141., 11., 205., 59., 52., 78., 61., 0.], [ 590., 146., 38., 292., 102., 102., 101., 97., 30.], [ 576., 160., 25., 267., 81., 58., 83., 38., 1.], [ 458., 127., 1., 154., 32., 48., 31., 34., 3.], [ 513., 136., 19., 220., 101., 66., 101., 54., 0.], [ 607., 155., 0., 179., 39., 74., 66., 63., 7.], [ 566., 157., 1., 183., 38., 38., 98., 22., 2.], [ 656., 175., 3., 229., 27., 80., 69., 46., 26.], [ 652., 162., 20., 268., 90., 98., 107., 84., 23.], [ 522., 131., 11., 191., 49., 80., 93., 38., 19.], [ 618., 163., 11., 232., 42., 58., 78., 33., 8.], [ 530., 136., 8., 193., 65., 48., 109., 27., 5.], [ 471., 114., 22., 202., 68., 63., 68., 44., 1.], [ 450., 108., 18., 190., 56., 69., 110., 49., 26.], [ 537., 123., 31., 236., 96., 64., 116., 72., 0.], [ 679., 154., 13., 216., 39., 102., 119., 77., 28.], [ 518., 127., 34., 258., 95., 66., 75., 24., 0.], [ 465., 109., 24., 205., 68., 48., 106., 39., 0.], [ 554., 127., 22., 213., 79., 58., 130., 48., 2.], [ 507., 116., 6., 165., 46., 38., 69., 27., 1.], [ 494., 103., 14., 171., 73., 61., 89., 72., 4.], [ 533., 106., 7., 145., 36., 49., 80., 75., 13.], [ 458., 81., 4., 107., 35., 27., 76., 36., 2.], [ 607., 178., 8., 242., 69., 74., 64., 68., 12.], [ 593., 155., 5., 196., 43., 76., 113., 73., 41.], [ 611., 172., 24., 284., 82., 73., 108., 38., 8.], [ 616., 163., 17., 240., 70., 79., 84., 75., 53.], [ 536., 131., 18., 224., 73., 82., 97., 100., 23.], [ 605., 169., 18., 242., 106., 62., 53., 38., 3.], [ 671., 171., 11., 244., 62., 98., 103., 77., 18.], [ 555., 145., 14., 213., 61., 66., 121., 42., 5.], [ 612., 140., 7., 184., 50., 69., 53., 99., 6.], [ 583., 143., 6., 195., 61., 62., 56., 50., 3.], [ 513., 129., 20., 214., 76., 56., 105., 47., 5.], [ 570., 139., 24., 238., 92., 81., 89., 64., 0.], [ 569., 133., 3., 176., 41., 52., 87., 83., 0.], [ 481., 118., 7., 173., 40., 56., 95., 30., 11.], [ 497., 116., 2., 141., 43., 39., 49., 61., 1.], [ 488., 110., 1., 130., 34., 51., 53., 42., 6.], [ 626., 147., 2., 169., 53., 61., 56., 69., 22.], [ 520., 122., 1., 143., 33., 64., 69., 40., 53.], [ 589., 137., 27., 247., 88., 74., 123., 58., 2.], [ 449., 108., 0., 131., 46., 27., 44., 19., 1.], [ 610., 142., 2., 178., 33., 63., 55., 56., 16.], [ 598., 144., 39., 282., 97., 71., 138., 44., 0.], [ 609., 142., 27., 256., 85., 79., 141., 48., 6.], [ 583., 129., 35., 260., 103., 73., 148., 59., 1.], [ 485., 106., 6., 145., 35., 44., 49., 46., 7.], [ 624., 142., 25., 245., 110., 61., 126., 47., 2.], [ 590., 122., 10., 184., 56., 74., 86., 47., 8.], [ 600., 115., 0., 127., 28., 66., 117., 63., 23.]])
打者項目によって数値の範囲にばらつきがあるため、平均0、分散1に標準化しておく。
でも、項目によって価値がだいぶ違うものもあるので、項目別のレンジ調整が必要かも…
>>> Xm = np.broadcast_to(X.mean(axis=0), X.shape) >>> Xs = np.broadcast_to(X.std(axis=0), X.shape) >>> Xv = (X - Xm) / Xs
固有ベクトル(v), 固有値(l)を求める。
>>> R1 = np.corrcoef(Xv.T) >>> l,v = np.linalg.eigh(R1)
ランクが見やすいように寄与率を算出する。
>>> l / l.sum() * 100 array([ 0.08933219, 1.01050674, 1.50297613, 2.19603783, 6.06787656, 8.22801916, 11.12005857, 23.43222355, 46.35296927])
寄与率が大きいものは、
第1主成分 (8) 46.4%
第2主成分 (7) 23.4%
第3主成分 (6) 11.1%
ここまでで 80.9%
選んだ3種類の主成分スコアを算出する。
>>> scr_8 = Xv * np.broadcast_to(v[::,8:9].T, X.shape) >>> scr_7 = Xv * np.broadcast_to(v[::,7:8].T, X.shape) >>> scr_6 = Xv * np.broadcast_to(v[::,6:7].T, X.shape)
3. 結果を見てみる。
第1主成分から第3主成分まで、作ってくれた物差しは以下のようなもの。
※直観的に野球成績と比較しやすいように正負の向きを逆にした。
第1主成分 (46.4%)
ケガなく出場し、安打打ちまくり、デカいのも打て、よく本塁に帰ってくる。
いわゆるオールマイティな選手
↓を見ると、確かに誰もがスゴイと納得する選手が上位に並んでいる。
第2主成分 (23.4%)
出場機会は少ないが、本塁打をよく打ち打点を稼ぐ。でも早打ち&選球眼イマイチで鈍足。
いわゆる当たれば飛ぶ一発屋タイプ
↓を見ると、確かに一発屋の助っ人外国人選手が上位に並んでいる。
第3主成分 (11.1%)
非力であまりヒットを打たないが、よく四球を選んで出塁し、盗塁で相手守備をかき乱す。
いわゆる???
難しいなぁ、リードオフマンタイプでもないしなぁ、巨人鈴木選手タイプか?
寄与率11%だからこんなもんか…
全55人を各物差しで測った結果は以下の通り。
x. 備忘録
リードオフマン物差しが出来なかったのが残念だ。
変量にリードオフマンの特徴を表すような項目を追加する必要がありそうだ。