【Pythonでセイバーメトリクス】福岡ソフトバンクホークス内川聖一選手を分析するの巻

プログラミング
LINEで送る
Pocket

はじめに

こんにちは!
今回はPythonを使う練習も兼ねて、何か実際のデータを分析したいと考えました。そこで、僕が大好きな野球選手の成績を使ってデータ分析をしてみたいと思います。

この記事は【初心者向け】33分4秒でおぼえる野球統計学とPyData〜陽岱鋼を添えての記事の流れを大いに参考にさせていただきました。

セイバーメトリクスについて

昨今、野球もデータ分析が盛んになってきており、セイバーメトリクスという分析手法が浸透しております。
Wikipediaによるとセイバーメトリクスは

セイバーメトリクス (SABRmetrics, Sabermetrics) とは、野球においてデータを統計学的見地から客観的に分析し、選手の評価や戦略を考える分析手法である。

とあります。
セイバーメトリクスの考え方でいくと、打者に関しては「アウトにならないこと」や「一つでも次の塁に進むこと」が重要視され、今まで野球で有効とされていた送りバントや盗塁のようなアウトになる確率が高い攻撃はあまり選ばれない傾向にあるようです。

内川聖一選手の年度別成績からセイバーメトリクス指標を算出

さて本題です。
今回は、僕が愛してやまない福岡ソフトバンクホークスの内川聖一選手の成績を使ってセイバーメトリクス指標を算出します。

ご存知の方もいらっしゃるかもしれませんが、内川選手は稀代のヒットメーカーです。過去には右打者として歴代最高打率の.378を叩き出したことでも有名です。しかし、今年は開幕前の練習試合での成績がよろしくなく、今シーズンは二軍生活を余儀なくされています。ただ、二軍では高打率をキープしており、近いうちに一軍に上がってくることを心から祈っています!

とりあえずそこで、改めて内川選手の特徴を年度別成績から浮き彫りにし、一軍に合流した際の起用方法に関して考えたいと思います。

もちろんのこと、ここでの考察は筆者の個人的見解になるので、あまり深く突っ込まないでくださいね…

必要な準備

とりあえず今回必要なPythonライブラリをインストールします。
僕はJupyter notebook上で全て行ったので、行頭に!をつけて操作しました。

!pip install ipython pandas beautifulsoup4 numpy lxml html5lib jupyter matplotlib seaborn

そうしたら、グラフをnotebook内に描画するために%matplotlib inlineと、pandasのインポート、表示行列を増やしました。

%matplotlib inline
import pandas as pd

# 表示行・列を増やす(30列、10行)
pd.get_option("display.max_columns", 30)
pd.get_option("display.max_rows", 10)

データ収集

以上の準備ができたら、内川選手のデータを入手しましょう。
データはNPB公式サイトの内川選手のページからスクレイピングします。(スクレイピングは用法用量に注意しましょう!

url = 'https://npb.jp/bis/players/21325113.html' #内川聖一選手の個人年度別成績(npb.jp)
df = pd.read_html(url) #Tableタグをスクレイピング。

dfには複数のTableが含まれます。df[0]には選手のプロフィールが、df[1]には年度別の成績が含まれています。

df[0] #選手のプロフィール
01
0ポジション内野手
1投打右投右打
2身長/体重185cm/93kg
3生年月日1982年8月4日
4経歴大分工
5ドラフト2000年ドラフト1位
df[1] #年度別の成績
年度所属球団試合打席打数得点安打二塁打三塁打本塁打...盗塁刺犠打犠飛四球死球三振併殺打打率長打率出塁率
02001.0横 浜32210000...00000000.0000.0000.000
12002.0横 浜4273661122412...030401310.3330.5150.371
22003.0横 浜451611502047504...460501310.3130.4270.335
32004.0横 浜94369338559711117...71211804270.2870.4760.322
42005.0横 浜9026223433641105...16119236100.2740.3850.332
52006.0横 浜124439402411151524...3732256490.2860.3630.329
62007.0横 浜9227424724691737...4411663790.2790.4570.337
72008.0横 浜1355445008318937114...3543144970.3780.5400.416
82009.0横 浜1325525036516032217...52442156160.3180.4910.369
92010.0横 浜144637577751823649...23447651170.3150.4380.371
102011.0福岡ソフトバンク1144634294814521312...0072524830.3380.4850.371
112012.0福岡ソフトバンク138567523441572137...40731636120.3000.3920.342
122013.0福岡ソフトバンク1446335707618033119...005461247230.3160.4770.376
132014.0福岡ソフトバンク1225344885015026118...0073454850.3070.4750.354
142015.0福岡ソフトバンク1365855296015024111...00745455240.2840.3950.340
152016.0福岡ソフトバンク1416055566216919018...20938253270.3040.4350.345
162017.0福岡ソフトバンク73300266317913012...1023202690.2970.4810.370
172018.0福岡ソフトバンク7129628127681108...103933260.2420.3670.270
182019.0福岡ソフトバンク1375355004912821012...01428249160.2560.3700.296
19NaN通 算197778317161855217135723196...374969492607552020.3030.4420.350

20 rows × 23 columns

前処理

データが取得できたので、前処理をしていきます。
まずは、一軍での試合数が少ない2003年以前と通算の成績を除外して、新しいデータフレームを作成します。

#不使用となるデータを捨てて、別のデータフレーム作成(一軍での試合数が少ない2003年以前と通算)
atbats = df[1].drop([0, 1, 2, 19], axis=0) 

そしたら、カラム名をおしゃれに野球英語にします。

日本語名英語名
年度year
所属球団team
試合g
打席pa
打数ab
得点r
安打h
二塁打_2b
三塁打_3b
本塁打hr
塁打tb
打点rbi
盗塁sb
盗塁刺cs
犠打sh
犠飛sf
四球bb
死球hbp
三振so
併殺打dp
打率ba
長打率slg
出塁率obp

ついでにデータ型もfloat型に変換します。

# カラム名を付与する(野球英語の略称)
atbats.columns = ['year', 'team', 'g', 'pa', 'ab', 'r', 'h', '_2b', '_3b', 'hr', 'tb', 'rbi', 'sb', 'cs', 'sh', 'sf', 'bb', 'hbp', 'so', 'dp', 'ba', 'slg', 'obp']

# 各カラムを前処理する
import numpy as np
atbats['year'] = atbats['year'].astype(np.float64)
atbats['g'] = atbats['g'].astype(np.float64)
atbats['pa'] = atbats['pa'].astype(np.float64)
atbats['ab'] = atbats['ab'].astype(np.float64)
atbats['r'] = atbats['r'].astype(np.float64)
atbats['h'] = atbats['h'].astype(np.float64)
atbats['_2b'] = atbats['_2b'].astype(np.float64)
atbats['_3b'] = atbats['_3b'].astype(np.float64)
atbats['hr'] = atbats['hr'].astype(np.float64)
atbats['tb'] = atbats['tb'].astype(np.float64)
atbats['rbi'] = atbats['rbi'].astype(np.float64)
atbats['sb'] = atbats['sb'].astype(np.float64)
atbats['cs'] = atbats['cs'].astype(np.float64)
atbats['sh'] = atbats['tb'].astype(np.float64)
atbats['sf'] = atbats['sf'].astype(np.float64)
atbats['bb'] = atbats['bb'].astype(np.float64)
atbats['hbp'] = atbats['hbp'].astype(np.float64)
atbats['so'] = atbats['so'].astype(np.float64)
atbats['dp'] = atbats['dp'].astype(np.float64)
atbats['ba'] = atbats['ba'].astype(np.float64)
atbats['slg'] = atbats['slg'].astype(np.float64)
atbats['obp'] = atbats['obp'].astype(np.float64)

セイバーメトリクス指標を可視化

データフレームができたので、セイバーメトリクス指標を可視化していきます。

ひとまず可視化にseabornを使用します。

# 可視化としてseabornを使用
import seaborn as sns

まずは、OPSとBB/Kを算出します。

OPS

OPSは打席あたりで得点増加に有効な打撃をしているかどうかを表す指標です。つまり打席での貢献度を示します。
平均は.730前後で、.1000を越えればリーグ最高レベルとのこと。

〈計算方法〉
OPS = 長打率 + 出塁率

BB/K

四球と三振の割合から打者の選球眼を見る指標です。1前後が望ましく、理想は1.5〜2とのこと。

〈計算方法〉
BB/K = 四球 / 三振

これらを計算していきます。

# OPSとBB/Kを計算

atbats['ops'] = atbats['obp'] + atbats['slg'] # OPS
atbats['bb_k'] = atbats['bb'] / atbats['so'] # BB/K

OPSの結果

atbats['ops']
3     0.798
4     0.717
5     0.692
6     0.794
7     0.956
8     0.860
9     0.809
10    0.856
11    0.734
12    0.853
13    0.829
14    0.735
15    0.780
16    0.851
17    0.637
18    0.666
Name: ops, dtype: float64
# OPSを折れ線グラフに
sns.pointplot(x="year", y="ops", data=atbats)

output_12_1

BB/Kの結果

atbats['bb_k']
3     0.428571
4     0.527778
5     0.343750
6     0.432432
7     0.632653
8     0.750000
9     0.921569
10    0.520833
11    0.861111
12    0.978723
13    0.708333
14    0.818182
15    0.716981
16    1.230769
17    0.281250
18    0.571429
Name: bb_k, dtype: float64
# BB/Kを折れ線グラフに
sns.pointplot(x="year", y="bb_k", data=atbats)

output_14_1

以上の結果からわかること

  • OPSは平均以上のことが多いが、打率の割にリーグトップレベルまでは行かない。
  • BB/Kの結果からは、四球が三振より多いとはあまり言えない。ただ、三振数は他の選手と比べて数は少ないので、極端に四球が少ないとも考えられる。

次はwOBAを見てみましょう。

wOBA

打者が打席あたりにどれだけチームの得点増に貢献する打撃をしているかを評価する指標です。安打や四球など出塁を伴う要素に得点価値を加重して算出されます。
出塁の価値を全て均一とみなす出塁率よりも打撃の貢献を総合的に表し、加重が統計的な根拠に基づいていることからOPSよりも適切に打撃の価値を評価すると言われています。
出塁率に合うように設計されているため、平均的な打者で.330程度になるようです。

〈計算式〉
wOBA = (0.7×(四球+死球)+0.9×単打+1.3×二塁打+1.6×三塁打+2.0×本塁打)÷(打数+四球+死球+犠飛)

(係数はシーズンによって変わるようですが、今回は数年の結果を見るのでベーシックな係数を使用しました。)

# wOBA
atbats['woba'] = ( 0.7 * ( atbats['bb'] + atbats['hbp'] ) + 0.9 * ( atbats['h'] ) + 1.3 * ( atbats['_2b']) + 1.6 * ( atbats['_3b']) + 2.0 * atbats['hr'] ) / ( atbats['ab'] + atbats['bb'] + atbats['hbp'] + atbats['sf'])
atbats['woba']
3     0.419608
4     0.377344
5     0.354398
6     0.438519
7     0.505195
8     0.459818
9     0.429180
10    0.443844
11    0.376190
12    0.450395
13    0.437640
14    0.383077
15    0.398017
16    0.448000
17    0.337500
18    0.351124
Name: woba, dtype: float64
# wOBAを折れ線グラフに
sns.pointplot(x="year", y="woba", data=atbats)

output_21_1

wOBAの結果からわかること

  • wOBAは、調子の悪かったここ2年を含めて平均以上。また、.400を超えることも多く、かなり高水準であることがわかる(2020年9月7日時点で柳田選手は.460、オリックスの吉田正尚選手は.451、日本ハムの中田翔選手は.401)。

では次はIsoPを見てみましょう。

IsoP

打者が長打(二塁打以上)を放つ能力を測る指標です。長打率から単打の要素を除くことでより純粋な長打力を測ることができます。安打が全てシングルヒットの場合は0になります。平均は.130程度になるようです。

〈計算式〉
IsoP = 長打率-打率

# IsoP
atbats['isop'] = atbats['slg'] - atbats['ba']
atbats['isop']
3     0.189
4     0.111
5     0.077
6     0.178
7     0.162
8     0.173
9     0.123
10    0.147
11    0.092
12    0.161
13    0.168
14    0.111
15    0.131
16    0.184
17    0.125
18    0.114
Name: isop, dtype: float64
# IsoPを折れ線グラフに
sns.pointplot(x="year", y="isop", data=atbats)

output_25_1

IsoPの結果からわかること

  • IsoPは、.200を越えることなく推移。長打がそこまで多くない選手といえる(2020年9月7日時点で中田翔選手は.340、柳田選手は.328)。

最後にIsoDを算出します。

IsoD

四死球によってどの程度出塁したかを測るための指標です。平均は.060程度になるようです。

〈計算式〉
IsoD = 出塁率-打率

# IsoD
atbats['isod'] = atbats['obp'] - atbats['ba']
atbats['isod']
3     0.035
4     0.058
5     0.043
6     0.058
7     0.038
8     0.051
9     0.056
10    0.033
11    0.042
12    0.060
13    0.047
14    0.056
15    0.041
16    0.073
17    0.028
18    0.040
Name: isod, dtype: float64
# IsoDを折れ線グラフに
sns.pointplot(x="year", y="isod", data=atbats)

output_29_1

IsoDの結果からわかること

  • IsoDは、平均の.060を下回ることがほとんどであり、四死球で出塁することは多いとはいえない。

考察

以上の結果から、内川選手の特徴として以下のことが挙げられると考えられます。

  • 四死球が極端に少ないが、wOBAが高く、安打での出塁の確率がかなり高い選手
  • ただし、ホームランなどの長打を打つというよりは単打や二塁打などが多い
  • つまり肩書きに負けない生粋の安打製造機
  • ただ、近年は調子は落ち気味?しかし、現在二軍では絶好調!

これを踏まえて、現時点で仮に一軍に合流した際のチームの打順を考えます。

  1. 周東(二)
  2. 柳田(中)
  3. 内川(一)
  4. グラシアル(三 or DH)
  5. 中村晃(左)
  6. 栗原(右)
  7. デスパイネ(DH) or 松田(三)
  8. 甲斐(捕)
  9. 川瀬(遊)

うーん、難しい…異論は認めます!笑
ただ、内川選手をどこに置くか考えると3番あたりがベストな気がします。


以上、Pythonを使って内川選手の年度別打撃成績をセイバーメトリクスで分析し、その特徴をとらえてみました。
セイバーメトリクスを使うことで、改めて違った見方で選手のことを見れそうです。勉強になりましたー!

LINEで送る
Pocket

コメント

タイトルとURLをコピーしました