【2023年】プロ野球のセリーグの戦績でデータ分析 ver2　〜打撃編〜

# はじめに
前回はスポーツナビの順位表からデータ分析をしました。
今回はNPBのサイトからデータを引用させていただきデータ分析2回目をしていきます。

前回の記事

https://qiita.com/wooooo/items/a52695b3df5e0ac374e5

# 引用したサイト
https://npb.jp/bis/2023/stats/std_c.html

得点圏打率はこちらから引用させていただきます

https://nf3.sakura.ne.jp/Stats/team_etc.htm

# 環境構築
```
pip install pandas numpy seaborn matplotlib japanize-matplotlib
```

# 各項目との相関係数
![スクリーンショット 2023-10-07 18.24.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/8b299921-8b12-f437-ed26-6a0ee18e499e.png)
得点と他の項目の相関係数をpandasのcorr()で求めた結果Top7がコチラ

|順位|項目|相関係数|
|--|--|--|
|1位| 打点| 1.00|
|2位| 出塁率| 0.96|
|3位|四球|0.78|
|4位| 打席|0.74|
|5位|犠飛|0.72|
|6位|打率|0.69|
|7位|長打率|0.64|

※相関係数は小数点第3位で四捨五入しています。

「3割バッター」だと1流という風潮がありますが、得点との相関に関しては出塁率や四球より低い相関があり、得点により結びつきにくそうに思えます。

犠飛の相関係数が4位で、投高打低の今季は犠牲フライの重要性が高まってきているかもしれません。
ちなみに、犠牲バントは0.63で長打率の次に相関係数が高いです。

野球は塁を進めて得点を重ねる競技なので、個人的に塁打という指標が好きですが、相関係数が0.59で低めです。

# 各項目と得点数とのグラフ
・出塁率
![Figure_出塁率-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/98920f8a-21d0-2e5a-a4d4-2361e36e15d2.png)

・四球
![Figure_四球と得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/00f9e24e-ad89-2eca-5d0d-162dd95bc97f.png)

・犠飛
![Figure_犠飛-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/dd30588d-85ef-151c-2ca4-80b5be470ba2.png)

・長打率
![Figure_長打率-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/c6347c9e-2292-d03f-49aa-8ee914d2513a.png)

・OPS(長打率+出塁率)
![Figure_OPSと得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/2c8cf9cf-e1dd-d4c3-ea32-a830da8ca440.png)

・ISO(IsoP)
安打数から単打を引いた打者の長打力を測る指数（長打率-打率)
![Figure_ISO-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/2f1f4008-5f45-0a6e-68a9-e542dc67f19a.png)

・BABIP
打者の運や守備の影響を除いた打撃能力を示す指標(安打-本塁打)/(打数-三振-本塁打+犠飛)
![Figure_BABIP-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/cb6ea1d3-7cce-8901-ca0d-39367753c81d.png)

・RC
打者がどれだけ得点を生み出したかの指標(安打+四球)x塁打/打席
![Figure_RC-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/e6650cff-605b-f840-dc16-222fc8a7eaa1.png)

# コード
データ分析に必要なライブラリをインポートします。
データはCSV形式で保存したファイルを読み込んでDataFrame型にします。
```python
import pandas as pd
import numpy as np
import seaborn as sns
from matplotlib import pyplot as plt
import japanize_matplotlib

# セリーグの順位表を読み込む
df = pd.read_csv('npb_tmb_c.csv')

# 凡例のチームカラーの設定
team_colors = {
    '阪神': 'yellow',
    '広島': 'red',
    'DeNA': 'blue',
    '巨人': 'orange',
    'ヤクルト': 'navy',
    '中日': 'cyan'
}

# チーム順位のカラムを追加
df['順位'] = ['4', '3', '1', '2', '5', '6']
df = df.sort_values(by='順位')
```

### 出塁率と得点のグラフ
```python
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='出塁率', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('出塁率と得点の関係')
plt.xlabel('出塁率')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['出塁率'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# 得点と失点の平均値を示す線を追加
plt.axvline(df['出塁率'].mean(), color='red', linestyle='--', label='出塁率の平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['出塁率'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['出塁率'], df['得点'], 1)
x = np.linspace(min(df['出塁率']), max(df['出塁率']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_出塁率-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/c7020452-cfdc-e78f-ea6a-bbbce952f036.png)
縦軸に出塁率、横軸に得点数のグラフです。
出塁率と得点の平均線をそれぞれ青、赤色で示しています。
各ポイントの左上の数字は順位を表しています。
相関係数が0.96で強い相関を示しています。

優勝した阪神は出塁率と得点がリーグ最多です。
また、0.96の相関係数があるように今季のセリーグで言えば出塁率が増えれば増えるほど得点が多くなってくると言えるでしょう。

巨人とヤクルトはリーグ平均より多くの得点と出塁率を記録していますが、それぞれ4位と5位となっています。

3位のDeNAは得点数はセリーグ平均より多いですが、出塁率より低い値となっています。来季は出塁率を高めれば、得点数を1位を狙えるかもしれません。

カープはリーグ平均よりも低い得点と出塁率を記録していますが、2位となっています。バントや進塁打、盗塁など他の進塁方法で効率的な攻撃しているのではないでしょうか。

最下位の中日はダントツの得点数と出塁率の低さです。今季はドラフト、トレード、FAで野手を補強して欲しいところです。

### 四球と得点のグラフ
```python
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='四球', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('四球と得点の関係')
plt.xlabel('四球')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['四球'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# 四球と得点の平均値を示す線を追加
plt.axvline(df['四球'].mean(), color='red', linestyle='--', label='四球の平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['四球'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['四球'], df['得点'], 1)
x = np.linspace(min(df['四球']), max(df['四球']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_四球と得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/9ec15527-4104-7eaa-f112-27d724f05497.png)
縦軸に四球数、横軸に得点数のグラフです。
相関係数が0.78で強い相関を示しています。

阪神は四球数がリーグ1位です。
「アレ」の要因は四球数が要因なのでしょうか？「そらそうよ」

5位のヤクルトは阪神同様にセリーグ平均を上回る四球数を記録しています。
四球で出塁という部分においては良い成績を収めました。
村上選手が90四球、サンタナ・オスナ・山田・青木・中村・長岡選手で200以上の四球を稼いでいます

DeNAと巨人、広島、中日はセリーグ平均以下の四球数でした。
DeNAと巨人はヤクルトに次いで得点数が多いだけに四球数が増加すれば阪神に匹敵する攻撃力になるのではないでしょうか。

広島は、DeNAと近い四球数が近いですが、得点数で差が大きいです。

中日は打てない、(四球を)選べない結果となりました。
今季の巨人のように、チーム安打数を増やすのか、もしくは四球数を増やすのか、どのような改善をするのでしょうか。

グラフを見る限り、ヤクルトや阪神のように四球が増えすぎても得点数が稼げないように見えます。四球は出塁の一手なだけで、基本的にバットをボールに当ててヒットゾーンに運ぶ技術が重要なのではないでしょうか。

# OPSと得点のグラフ
```python
df['OPS'] = df['出塁率'].astype(float) + df['長打率'].astype(float)
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='OPS', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('OPSと得点の関係')
plt.xlabel('OPS')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['OPS'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# OPSと得点の平均値を示す線を追加
plt.axvline(df['OPS'].mean(), color='red', linestyle='--', label='OPSの平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['OPS'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['OPS'], df['得点'], 1)
x = np.linspace(min(df['OPS']), max(df['OPS']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_OPSと得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/1648723a-a452-4d40-a929-084ec4ae5052.png)
縦軸にOPS、横軸に得点数のグラフです。
相関係数が0.85で強い相関を示しています。

OPSは出塁率と長打率を足した値で、どのくらいチームの得点に貢献したかの指標です。

阪神はリーグ平均より高いOPSを記録しています。

DeNAや巨人、ヤクルトもリーグ平均以上のOPSを記録しています。
特に巨人はリーグ1位のOPSを誇ります。来季の打撃陣はどうなるのでしょうか。

広島と中日はリーグ平均より低いOPSを示しています。

### 長打率と得点の関係
```python
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='長打率', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('長打率と得点の関係')
plt.xlabel('長打率')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['長打率'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# 長打率と得点の平均値を示す線を追加
plt.axvline(df['長打率'].mean(), color='red', linestyle='--', label='長打率の平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['長打率'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['長打率'], df['得点'], 1)
x = np.linspace(min(df['長打率']), max(df['長打率']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_長打率-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/bee74f13-7a8d-d571-4c2d-2504ac32734e.png)
縦軸に長打率、横軸に得点数のグラフです。
相関係数が0.64で正の相関を示しています。

阪神はリーグ平均より低い長打率ですが、リーグ最多の得点数を記録しています。

長打率は出塁率やOPSに比べて弱い相関を示しています。得点性が関連性と低いのでしょうか。
長打率は単打(シングルヒット)を含んでいるので、単打を除いた長打の割合を示したISOを見てみます。

### ISOと得点のグラフ
```python
df['ISO'] = df['長打率'] - df['打率']
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='ISO', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('ISOと得点の関係')
plt.xlabel('ISO')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['ISO'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# ISOと得点の平均値を示す線を追加
plt.axvline(df['ISO'].mean(), color='red', linestyle='--', label='ISOの平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['ISO'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['ISO'], df['得点'], 1)
x = np.linspace(min(df['ISO']), max(df['ISO']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_ISO-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/900502b8-95bb-d1bc-60e5-77b3268b5e01.png)
縦軸にISO、横軸に得点数のグラフです。
相関係数が0.57で正の相関を示しています。

ISOは長打率より低い相関を示しています。今年の数値で見ると長打を打つこととはより得点を挙げることとは関係が低くなるようです。

### BABIPと得点のグラフ
```python
df['BABIP'] = (df['安打'] - df['本塁打']) / (df['打数'] - df['三振'] - df['本塁打'] + df['犠飛'])
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='BABIP', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('BABIPと得点の関係')
plt.xlabel('BABIP')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['BABIP'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# BABIPと得点の平均値を示す線を追加
plt.axvline(df['BABIP'].mean(), color='red', linestyle='--', label='BABIPの平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['BABIP'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['BABIP'], df['得点'], 1)
x = np.linspace(min(df['BABIP']), max(df['BABIP']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_BABIP-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/218434aa-540e-eb36-fbb8-7edf16e96d64.png)
縦軸にBABIP、横軸に得点数のグラフです。
相関係数が0.44で正の相関を示しています。

BABIPは打者の運や守備の影響を除いた打撃能力を示す指標で、
(安打-本塁打)/(打数-三振-本塁打+犠飛)で計算されます。

阪神は先ほどの長打率・ISOとは異なり、リーグ平均以上の値を記録しています。
広島も四球など少ないですが、高いBABIPを記録しています。

セリーグで高めの打撃力を記録していたヤクルトですが、BABIPで見るとリーグ最低の記録でした。
連続で最下位を記録していた中日はリーグ5位の記録でした。


### RCと得点のグラフ
```python
df['RC'] = (df['安打'] + df['四球']) * df['塁打'] / df['打席']
plt.figure(figsize=(10, 5))
sns.scatterplot(data=df, x='RC', y='得点', hue='チーム', palette=team_colors, s=100)
plt.title('RCと得点の関係')
plt.xlabel('RC')
plt.ylabel('得点')
plt.grid(True)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
for i, row in df.iterrows():
    plt.text(
        row['RC'], row['得点'], str(row['順位']), color='black',
        fontsize=10, ha='right', va='bottom'
    )
# RCと得点の平均値を示す線を追加
plt.axvline(df['RC'].mean(), color='red', linestyle='--', label='RCの平均')
plt.axhline(df['得点'].mean(), color='blue', linestyle='--', label='得点の平均')
#  相関係数
correlation_coefficient = np.corrcoef(df['RC'], df['得点'])[0, 1]
plt.text(0.1, 0.9, f'r: {correlation_coefficient:.2f}', transform=plt.gca().transAxes)
# 回帰直線
slope, intercept = np.polyfit(df['RC'], df['得点'], 1)
x = np.linspace(min(df['RC']), max(df['RC']), 100)
y = slope * x + intercept
plt.plot(x, y, color='black', label=f'回帰直線: y = {slope:.2f}x + {intercept:.2f}', alpha=0.2)
plt.show()
```
![Figure_RC-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/35f07186-55f3-dfb3-3498-9b6ee4a5163d.png)
縦軸にRC、横軸に得点数のグラフです。
相関係数が0.79で強い相関を示しています。

OPSと同じような分布となっています。

# おわりに
近年はセイバーメトリクスの普及で、メディアでもISOやwOBAなど新しい指標が目にする機会が増えてきました。
打者や投手を評価する指標として見ると、より細かく別の視点で見ることができ興味深さは増しますが、得点や失点に関係するかというと従来の指標の方が高いという指標が多かったです。
あくまで相関係数で因果関係ではないため他のデータを見ながら選手を評価していき、より精度の高い分析の到来を心待ちにしたいです。

# おまけ
![Figure_BB:K-得点.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/95d679b9-dd30-afca-464e-c2281048f1fd.png)
BB/Kという打者の選球眼の指標と得点数とのグラフです。

四球が多い阪神がダントツかと思いましたが、DeNAやヤクルトのBB/Kも高いです。
DeNAは四球数と比べてリーグ内で高い値を示しているので早打ちだったりコンタクト率が高い傾向なんでしょうか。

# 関連記事
投手編

https://qiita.com/wooooo/items/27792fc182940ee3caa4

守備編

https://qiita.com/wooooo/items/8352a0f77c36f8c8728b