python勉強
2023/04/01 vs LAA (Los Angeles Angels)
藤浪投手のデータをチェック
勝手な分析をしてみた
- 7人目の3回はじめのバッターで、ストレートが抜けるような状態 (回転数が落ちていた) で四球
- 7人目以降から、スライダーもリリースポイントが引っ掛かり気味で、ホームベース上でもキャッチャー右側に行っている
- ストライクを取りに行った?真ん中付近に集まってきた球を痛打される
以下からは、備忘録としてのコード
4/1 データ
!pip install pybaseball
from pybaseball import statcast
df = statcast(start_dt='2023-03-30', end_dt='2023-4-1')
df_660261 = df[df['pitcher'] == 660261]
投げた球種
import pandas as pd
from pybaseball import statcast_pitcher
# fujinami 660261 のデータを取得
start_date = '2023-04-01'
end_date = '2023-04-01'
player_id = 660261
df = statcast_pitcher(start_dt=start_date, end_dt=end_date, player_id=player_id)
# 4/1の投球結果を抽出
df_660261 = df[df['pitcher'] == player_id]
# df_660261のpitch_typeカラムに含まれるユニークな球種を確認する
unique_pitch_types = df_660261['pitch_type'].unique()
# 確認した球種を表示する
print(unique_pitch_types)
Gathering Player Data
['FF' 'SL' 'FS' 'ST']
-
'FF' - Four-Seam Fastball(フォーシーム・ファストボール):
一般的な速球で、平直な軌道を描くことが多いです。高速で、回転数が多く、制球力が高いため、投手にとって信頼性が高い球種です。 -
'SL' - Slider(スライダー):
横方向に大きく曲がる変化球で、高速でスピンがかかっています。スライダーは、ファストボールよりも速度が遅く、縦横に曲がる特徴があります。バッターにとって、スライダーは見極めが難しく、スイングアンドミスが多く発生する球種です。 -
'FS' - Split-Finger Fastball(スプリット・フィンガー・ファストボール):
もしくはフォークボールとも呼ばれる変化球で、速球よりも速度が遅く、急激に下方向に落ちる特徴があります。投手は、指をボールの両側に広げて投げることで、この変化を生み出します。バッターにとっては、タイミングが難しく、空振りやゴロを誘発する効果があります。 -
'ST' - Sinker(シンカー):
ファストボールに似た球種ですが、速度がやや遅く、縦方向に落ちる特徴があります。シンカーは、バッターに対して低い位置でゴロを打たせる効果があり、ディフェンスの力を活かすことができます。
投球データ
import pandas as pd
# 左打者と右打者に対する投球データを抽出
df_660261_L = df_660261[df_660261['stand'] == 'L']
df_660261_R = df_660261[df_660261['stand'] == 'R']
# 各カテゴリーでの球種の出現回数をカウント
total_counts = df_660261['pitch_type'].value_counts()
left_counts = df_660261_L['pitch_type'].value_counts()
right_counts = df_660261_R['pitch_type'].value_counts()
# 出現回数をデータフレームにまとめる
pitch_counts_table = pd.DataFrame({'Total': total_counts, 'Left Batter': left_counts, 'Right Batter': right_counts})
# NaNを0に置き換える
pitch_counts_table.fillna(0, inplace=True)
# カウントを整数に変換する
pitch_counts_table = pitch_counts_table.astype(int)
# 結果を表示
print(pitch_counts_table)
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
# カラーマップを定義
colors = {'FF': 'red', 'SL': 'blue', 'FS': 'green', 'ST': 'orange'}
# vs Left batter
df_660261_L['pitch_type'].value_counts().plot(kind='pie', ax=axs[0], autopct='%.1f%%', colors=[colors[key] for key in df_660261_L['pitch_type'].value_counts().index])
axs[0].set_title('vs Left batter')
axs[0].set_ylabel('') # y軸ラベルを削除
# vs Right batter
df_660261_R['pitch_type'].value_counts().plot(kind='pie', ax=axs[1], autopct='%.1f%%', colors=[colors[key] for key in df_660261_R['pitch_type'].value_counts().index])
axs[1].set_title('vs Right batter')
axs[1].set_ylabel('') # y軸ラベルを削除
plt.show()
コース
import matplotlib.pyplot as plt
# データを pitch_type ごとにグループ分けする
grouped = df_660261.groupby('pitch_type')
# pitch_type ごとに、'plate_x' を X 軸、'plate_z' を Y 轴とした散布図を作成する
for pitch_type, data in grouped:
plt.scatter(data['plate_x'], data['plate_z'], label=pitch_type)
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
plt.fill(x, y, color='r', alpha=0.1)
# 凡例を表示する
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
plt.xlim(-3, 3)
plt.ylim(-2, 6)
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
# 罫線
plt.grid(which='both', linestyle='--', color='gray', alpha=0.5)
# グラフを表示する
plt.show()
リリースポイント
投手が投球した際のリリースポイント(投球時のボールが手から離れる位置)を示しています。
import matplotlib.pyplot as plt
# データを pitch_type ごとにグループ分けする
grouped = df_660261.groupby('pitch_type')
# pitch_type ごとに、'release_pos_x' を X 軸、'release_pos_z' を Y 軸とした散布図を作成する
for pitch_type, data in grouped:
plt.scatter(data['release_pos_x'], data['release_pos_z'], label=pitch_type)
# 凡例を表示する
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
plt.xlabel('Release Pos X')
plt.ylabel('Release Pos Z')
# 罫線
plt.grid(which='both', linestyle='--', color='gray', alpha=0.5)
# グラフを表示する
plt.show()
イニングごとのコース
3回からのスライダーのバラツキ
import matplotlib.pyplot as plt
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
# イニングごとに散布図を作成
for inning, data_by_inning in grouped_by_inning:
# イニングのサブプロットを取得
ax = axs[(inning - 1) // ncols, (inning - 1) % ncols]
# ストライクゾーンを表示
ax.fill(x, y, color='r', alpha=0.1)
# イニングのデータを球種でグループ分け
grouped_by_pitch_type = data_by_inning.groupby('pitch_type')
# 各球種ごとに散布図を作成
for pitch_type, data in grouped_by_pitch_type:
ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type)
# サブプロットのタイトルを設定
ax.set_title(f'Inning {inning}')
# X 軸と Y 軸の範囲を設定
ax.set_xlim(-3, 3)
ax.set_ylim(-2, 6)
# X 軸と Y 軸のラベルを設定
ax.set_xlabel('Plate X')
ax.set_ylabel('Plate Z')
# 凡例を表示
ax.legend()
# 目盛り線を表示
ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)
# グラフを表示
plt.show()
イニングごとのリリースポイント
import matplotlib.pyplot as plt
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# イニングごとに散布図を作成
for inning, data_by_inning in grouped_by_inning:
# イニングのサブプロットを取得
ax = axs[(inning - 1) // ncols, (inning - 1) % ncols]
# イニングのデータを球種でグループ分け
grouped_by_pitch_type = data_by_inning.groupby('pitch_type')
# 各球種ごとに散布図を作成
for pitch_type, data in grouped_by_pitch_type:
ax.scatter(data['release_pos_x'], data['release_pos_z'], label=pitch_type)
# サブプロットのタイトルを設定
ax.set_title(f'Inning {inning}')
# 凡例を表示
ax.legend()
# 目盛り線を設定
ax.grid(color='gray', linestyle='--', linewidth=0.5)
# X 軸と Y 軸のラベルを設定
plt.setp(axs[-1, :], xlabel='Release Pos X')
plt.setp(axs[:, 0], ylabel='Release Pos Z')
# グラフを表示
plt.show()
イニングごとのリリース 球種べつ
スライダーのリリースがキャッチャーから見て、右側にずれていることが分かる。
投球コースも右側にずれているため、相関があると思われる
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ID 660261 のデータを対戦した打者ごとに分割する
batter_groups = df_660261.groupby('at_bat_number')
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# 色のリストを用意
colors = plt.cm.get_cmap('tab10')(np.linspace(0, 1, max_inning))
# 各球種ごとにグラフを作成
for i, pitch_type in enumerate(pitch_types):
# サブプロットを作成
ax = axs[i // ncols, i % ncols]
# 各イニングごとにデータをグループ分け
grouped_by_pitch_type = [data_by_inning[data_by_inning['pitch_type'] == pitch_type].groupby('inning') for _, data_by_inning in grouped_by_inning]
# 各イニングごとに散布図を作成
for j, (inning, data_by_pitch_type) in enumerate(zip(range(1, max_inning+1), grouped_by_pitch_type)):
data = pd.concat([data_by_pitch_type.get_group(x) for x in data_by_pitch_type.groups], ignore_index=True)
ax.scatter(data['release_pos_x'], data['release_pos_z'], label=f'Inning {inning}', color=colors[j])
# サブプロットのタイトルを設定
ax.set_title(f'Pitch Type: {pitch_type}')
# 凡例を表示
ax.legend()
# 目盛り線を描画
ax.xaxis.grid(color='gray', linestyle='--', linewidth=0.5)
ax.yaxis.grid(color='gray', linestyle='--', linewidth=0.5)
# X 軸と Y 軸のラベルを設定
plt.setp(axs[-1, :], xlabel='Release Pos X')
plt.setp(axs[:, 0], ylabel='Release Pos Z')
# グラフを表示
plt.show()
イニングごとのコース 球種べつ
スライダーがリリースがずれた方向に、コースもばらついている
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ID 660261 のデータを対戦した打者ごとに分割する
batter_groups = df_660261.groupby('at_bat_number')
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# 色のリストを用意
colors = plt.cm.get_cmap('tab10')(np.linspace(0, 1, max_inning))
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
# 各球種ごとにグラフを作成
for i, pitch_type in enumerate(pitch_types):
# サブプロットを作成
ax = axs[i // ncols, i % ncols]
# ストライクゾーンを描画
ax.fill(x, y, color='r', alpha=0.1)
# 各イニングごとにデータをグループ分け
grouped_by_pitch_type = [data_by_inning[data_by_inning['pitch_type'] == pitch_type].groupby('inning') for _, data_by_inning in grouped_by_inning]
# 各イニングごとに散布図を作成
for j, (inning, data_by_pitch_type) in enumerate(zip(range(1, max_inning+1), grouped_by_pitch_type)):
data = pd.concat([data_by_pitch_type.get_group(x) for x in data_by_pitch_type.groups], ignore_index=True)
ax.scatter(data['plate_x'], data['plate_z'], label=f'Inning {inning}', color=colors[j])
# サブプロットのタイトルを設定
ax.set_title(f'Pitch Type: {pitch_type}')
# 凡例を表示
ax.legend()
# 目盛り線を描画
ax.xaxis.grid(color='gray', linestyle='--', linewidth=0.5)
ax.yaxis.grid(color='gray', linestyle='--', linewidth=0.5)
# X 軸と Y 軸のラベルを設定
plt.setp(axs[-1, :], xlabel='Plate X')
plt.setp(axs[:, 0], ylabel='Plate Z')
# グラフを表示
plt.show()
ヒットを打たれたコース&球種 (イニングごと)
ヒットを打たれた5本の内訳
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ID 660261 のデータを対戦した打者ごとに分割する
batter_groups = df_660261.groupby('at_bat_number')
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
# 各球種ごとにグラフを作成
for i, pitch_type in enumerate(pitch_types):
# サブプロットを作成
ax = axs[i // ncols, i % ncols]
# ストライクゾーンを描画
ax.fill(x, y, color='r', alpha=0.3)
# 各イニングごとにデータをグループ分け
grouped_by_pitch_type = [data_by_inning[data_by_inning['pitch_type'] == pitch_type].groupby('inning') for _, data_by_inning in grouped_by_inning]
# 各イニングごとに散布図を作成
for j, (inning, data_by_pitch_type) in enumerate(zip(range(1, max_inning+1), grouped_by_pitch_type)):
data = pd.concat([data_by_pitch_type.get_group(x) for x in data_by_pitch_type.groups], ignore_index=True)
hit_data = data[data['events'].isin(['home_run', 'double', 'triple', 'single'])]
non_hit_data = data[~data['events'].isin(['home_run', 'double', 'triple', 'single'])]
ax.scatter(non_hit_data['plate_x'], non_hit_data['plate_z'], color='blue', alpha=0.7)
ax.scatter(hit_data['plate_x'], hit_data['plate_z'], color='red', alpha=0.7)
# サブプロットのタイトルを設定
ax.set_title(f'Pitch Type: {pitch_type}')
# 目盛り線を描画
ax.xaxis.grid(color='gray', linestyle='--', linewidth=0.5)
ax.yaxis.grid(color='gray', linestyle='--', linewidth=0.5)
# ヒットと非ヒットの凡例を追加
from matplotlib.lines import Line2D
legend_elements = [Line2D([0], [0], marker='o', color='w', label='Non-Hit', markerfacecolor='blue', markersize=8),
Line2D([0], [0], marker='o', color='w', label='Hit', markerfacecolor='red', markersize=8)]
# 凡例を表示
axs[0, 0].legend(handles=legend_elements, loc='upper right')
# X 軸と Y 軸のラベルを設定
plt.setp(axs[-1, :], xlabel='Plate X')
plt.setp(axs[:, 0], ylabel='Plate Z')
# グラフを表示
plt.show()
イニングごとの球種内訳
3回はスライダーが不安定だったのに、多く投げてしまったことが悪い影響になってしまったようにも見える
import matplotlib.pyplot as plt
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = (max_inning + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# カラーマップを定義
colors = {'FF': 'red', 'SL': 'blue', 'FS': 'green', 'ST': 'orange'}
# イニングごとにデータをグループ分け
grouped_by_inning = df_660261.groupby('inning')
# イニングごとに円グラフを作成
for inning, data_by_inning in grouped_by_inning:
# イニングのサブプロットを取得
ax = axs[(inning - 1) // ncols, (inning - 1) % ncols]
# イニングのデータを球種でカウント
pitch_type_counts = data_by_inning['pitch_type'].value_counts()
# イニングのデータで円グラフを作成
pitch_type_counts.plot(kind='pie', ax=ax, autopct='%.1f%%', colors=[colors[key] for key in pitch_type_counts.index])
# サブプロットのタイトルを設定
ax.set_title(f'Inning {inning}')
# Y 軸ラベルを削除
ax.set_ylabel('')
# グラフを表示
plt.show()
イニングごとの球種内訳 (vs 左右)
import matplotlib.pyplot as plt
# 左打者と右打者のデータを分割
df_660261_L = df_660261[df_660261['stand'] == 'L']
df_660261_R = df_660261[df_660261['stand'] == 'R']
# 最大イニング数を取得
max_inning = df_660261['inning'].max()
# サブプロットの行数と列数を設定
nrows = max_inning
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# カラーマップを定義
colors = {'FF': 'red', 'SL': 'blue', 'FS': 'green', 'ST': 'orange'}
# 左打者および右打者のデータをイニングごとにグループ分け
grouped_by_inning_L = df_660261_L.groupby('inning')
grouped_by_inning_R = df_660261_R.groupby('inning')
# イニングごとに円グラフを作成
for inning in range(1, max_inning + 1):
# 左打者
if inning in grouped_by_inning_L.groups:
data_by_inning_L = grouped_by_inning_L.get_group(inning)
pitch_type_counts_L = data_by_inning_L['pitch_type'].value_counts()
ax_L = axs[inning - 1, 0]
pitch_type_counts_L.plot(kind='pie', ax=ax_L, autopct='%.1f%%', colors=[colors[key] for key in pitch_type_counts_L.index])
ax_L.set_title(f'Inning {inning} vs Left batter')
ax_L.set_ylabel('')
# 右打者
if inning in grouped_by_inning_R.groups:
data_by_inning_R = grouped_by_inning_R.get_group(inning)
pitch_type_counts_R = data_by_inning_R['pitch_type'].value_counts()
ax_R = axs[inning - 1, 1]
pitch_type_counts_R.plot(kind='pie', ax=ax_R, autopct='%.1f%%', colors=[colors[key] for key in pitch_type_counts_R.index])
ax_R.set_title(f'Inning {inning} vs Right batter')
ax_R.set_ylabel('')
# グラフを表示
plt.show()
イニングごとの球種コース内訳 (vs 左右)
import numpy as np
import matplotlib.pyplot as plt
df_660261_L = df_660261[df_660261['stand'] == 'L']
df_660261_R = df_660261[df_660261['stand'] == 'R']
pitch_types_L = [pt for pt in df_660261_L['pitch_type'].unique() if not pd.isna(pt)]
pitch_types_R = [pt for pt in df_660261_R['pitch_type'].unique() if not pd.isna(pt)]
pitch_types = sorted(set(pitch_types_L) | set(pitch_types_R))
fig, axs = plt.subplots(len(pitch_types), 2, figsize=(12, len(pitch_types) * 4))
for i, pitch_type in enumerate(pitch_types):
df_660261_L_pt = df_660261_L[df_660261_L['pitch_type'] == pitch_type]
df_660261_R_pt = df_660261_R[df_660261_R['pitch_type'] == pitch_type]
axs[i, 0].scatter(df_660261_L_pt['plate_x'], df_660261_L_pt['plate_z'], label=pitch_type)
axs[i, 1].scatter(df_660261_R_pt['plate_x'], df_660261_R_pt['plate_z'], label=pitch_type)
axs[i, 0].set_xlim(-3, 3)
axs[i, 0].set_ylim(-2, 6)
axs[i, 1].set_xlim(-3, 3)
axs[i, 1].set_ylim(-2, 6)
axs[i, 0].set_xlabel('Plate X')
axs[i, 0].set_ylabel('Plate Z')
axs[i, 1].set_xlabel('Plate X')
axs[i, 1].set_ylabel('Plate Z')
axs[i, 0].legend()
axs[i, 1].legend()
axs[i, 0].grid(which='both', linestyle='--', color='gray', alpha=0.5)
axs[i, 1].grid(which='both', linestyle='--', color='gray', alpha=0.5)
axs[i, 0].set_title(f"Left Batter - {pitch_type}")
axs[i, 1].set_title(f"Right Batter - {pitch_type}")
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
axs[i, 0].fill(x, y, color='r', alpha=0.1)
axs[i, 1].fill(x, y, color='r', alpha=0.1)
plt.tight_layout()
plt.show()
イニングごとの各球種スピンレート / Boxplot
import matplotlib.pyplot as plt
import numpy as np
# ID 660261 のデータをイニングごとに分割する
inning_groups = df_660261.groupby('inning')
# イニングの最大値を取得する
max_inning = df_660261['inning'].max()
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 各球種に対してボックスプロットを作成する
fig, axs = plt.subplots(len(pitch_types), 1, figsize=(12, len(pitch_types) * 4))
for i, pitch_type in enumerate(pitch_types):
ax = axs[i]
position = 1
xticklabels = []
for inning, inning_data in inning_groups:
pitch_type_data = inning_data[inning_data['pitch_type'] == pitch_type]
if not pitch_type_data.empty:
pitch_type_data.boxplot(column='release_spin_rate', by='pitch_type', ax=ax, positions=[position])
# 平均値を計算し、表示する
mean_val = np.mean(pitch_type_data['release_spin_rate'])
ax.text(position, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')
# 対戦した打者数を計算する
unique_batters_count = inning_data['at_bat_number'].nunique()
xticklabels.append(f"Inning {inning}: {unique_batters_count} batters")
position += 1
ax.set_xticklabels(xticklabels)
ax.set_title(f"Pitch Type: {pitch_type}")
ax.set_xlabel('Inning')
ax.set_ylabel('Release Spin Rate')
fig.suptitle('Pitcher Fujinami: Release Spin Rate by Inning and Pitch Type', fontsize=16, y=1.02)
plt.tight_layout()
plt.show()
イニングごとの各球種の球速 / Boxplot
import matplotlib.pyplot as plt
import numpy as np
# ID 660261 のデータをイニングごとに分割する
inning_groups = df_660261.groupby('inning')
# イニングの最大値を取得する
max_inning = df_660261['inning'].max()
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 各球種に対してボックスプロットを作成する
fig, axs = plt.subplots(len(pitch_types), 1, figsize=(12, len(pitch_types) * 4))
for i, pitch_type in enumerate(pitch_types):
ax = axs[i]
position = 1
xticklabels = []
for inning, inning_data in inning_groups:
pitch_type_data = inning_data[inning_data['pitch_type'] == pitch_type]
if not pitch_type_data.empty:
pitch_type_data.boxplot(column='release_speed', by='pitch_type', ax=ax, positions=[position])
# 平均値を計算し、表示する
mean_val = np.mean(pitch_type_data['release_speed'])
ax.text(position, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')
# 対戦した打者数を計算する
unique_batters_count = inning_data['at_bat_number'].nunique()
xticklabels.append(f"Inning {inning}: {unique_batters_count} batters")
position += 1
ax.set_xticklabels(xticklabels)
ax.set_title(f"Pitch Type: {pitch_type}")
ax.set_xlabel('Inning')
ax.set_ylabel('Release Speed')
fig.suptitle('Pitcher Fujinami: Release Speed by Inning and Pitch Type', fontsize=16, y=1.02)
plt.tight_layout()
plt.show()
各打者ごとの各球種のスピンレート / Boxplot
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ID 660261 のデータを対戦した打者ごとに分割する
batter_groups = df_660261.groupby('at_bat_number')
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 各球種に対してボックスプロットを作成する
fig, axs = plt.subplots(len(pitch_types), 1, figsize=(12, len(pitch_types) * 6))
for i, pitch_type in enumerate(pitch_types):
ax = axs[i]
position = 1
# 'release_spin_rate'の最小値と最大値を取得(0を除く)
min_spin_rate = df_660261[df_660261['pitch_type'] == pitch_type]['release_spin_rate'].replace(0, np.nan).min()
max_spin_rate = df_660261[df_660261['pitch_type'] == pitch_type]['release_spin_rate'].max()
for at_bat_number, batter_data in batter_groups:
pitch_type_data = batter_data[batter_data['pitch_type'] == pitch_type]
if pitch_type_data.empty:
pitch_type_data = pd.DataFrame(columns=['pitch_type', 'release_spin_rate']) # ここを修正
pitch_type_data['pitch_type'] = [pitch_type] # ここを修正
pitch_type_data.boxplot(column='release_spin_rate', by='pitch_type', ax=ax, positions=[position])
# 平均値を計算し、表示する
mean_val = np.mean(pitch_type_data['release_spin_rate'])
ax.text(position, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')
position += 1
ax.set_title(f"Pitch Type: {pitch_type}")
ax.set_xlabel('Batter')
ax.set_ylabel('Release Spin Rate')
ax.set_xticklabels(range(1, position))
# Y軸の範囲を設定
ax.set_ylim(min_spin_rate, max_spin_rate)
# グラフ描画部分の後に以下を追加
ymin, ymax = ax.get_ylim()
y_range = ymax - ymin
ax.set_ylim(ymin - 0.05 * y_range, ymax + 0.1 * y_range)
plt.subplots_adjust(hspace=0.5)
plt.show()
各打者ごとの各球種の球速 / Boxplot
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ID 660261 のデータを対戦した打者ごとに分割する
batter_groups = df_660261.groupby('at_bat_number')
# ユニークな球種を取得する
pitch_types = df_660261['pitch_type'].dropna().unique()
# 各球種に対してボックスプロットを作成する
fig, axs = plt.subplots(len(pitch_types), 1, figsize=(12, len(pitch_types) * 6))
for i, pitch_type in enumerate(pitch_types):
ax = axs[i]
position = 1
# 'release_speed'の最小値と最大値を取得(0を除く)
min_spin_rate = df_660261[df_660261['pitch_type'] == pitch_type]['release_speed'].replace(0, np.nan).min()
max_spin_rate = df_660261[df_660261['pitch_type'] == pitch_type]['release_speed'].max()
for at_bat_number, batter_data in batter_groups:
pitch_type_data = batter_data[batter_data['pitch_type'] == pitch_type]
if pitch_type_data.empty:
pitch_type_data = pd.DataFrame(columns=['pitch_type', 'release_speed']) # ここを修正
pitch_type_data['pitch_type'] = [pitch_type] # ここを修正
pitch_type_data.boxplot(column='release_speed', by='pitch_type', ax=ax, positions=[position])
# 平均値を計算し、表示する
mean_val = np.mean(pitch_type_data['release_speed'])
ax.text(position, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')
position += 1
ax.set_title(f"Pitch Type: {pitch_type}")
ax.set_xlabel('Batter')
ax.set_ylabel('release_speed')
ax.set_xticklabels(range(1, position))
# Y軸の範囲を設定
ax.set_ylim(min_spin_rate, max_spin_rate)
# グラフ描画部分の後に以下を追加
ymin, ymax = ax.get_ylim()
y_range = ymax - ymin
ax.set_ylim(ymin - 0.05 * y_range, ymax + 0.1 * y_range)
plt.subplots_adjust(hspace=0.5)
plt.show()
各打者ごとの各球種、コース
import matplotlib.pyplot as plt
import itertools
# 対戦打者数を取得
batters = df_660261['at_bat_number'].unique()
num_batters = len(batters)
# サブプロットの行数と列数を設定
nrows = (num_batters + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# 対戦打者ごとにデータをグループ分け
grouped_by_batter = df_660261.groupby('at_bat_number')
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
# 球種ごとの色を自動的に割り当てる
pitch_types = df_660261['pitch_type'].unique()
pitch_colors = {pitch_type: color for pitch_type, color in zip(pitch_types, itertools.cycle(plt.rcParams['axes.prop_cycle']))}
# 対戦打者ごとに散布図を作成
for i, (at_bat_number, data_by_batter) in enumerate(grouped_by_batter):
# 対戦打者のサブプロットを取得
ax = axs[i // ncols, i % ncols]
# ストライクゾーンを表示
ax.fill(x, y, color='r', alpha=0.1)
# 対戦打者のデータを球種でグループ分け
grouped_by_pitch_type = data_by_batter.groupby('pitch_type')
# 各球種ごとに散布図を作成
for pitch_type, data in grouped_by_pitch_type:
ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type, color=pitch_colors[pitch_type]['color'])
# サブプロットのタイトルを設定
ax.set_title(f'Batter {i + 1}')
# X 軸と Y 軸の範囲を設定
ax.set_xlim(-3, 3)
ax.set_ylim(-2, 6)
# X 軸と Y 軸のラベルを設定
ax.set_xlabel('Plate X')
ax.set_ylabel('Plate Z')
# 凡例を表示
ax.legend()
# 目盛り線を表示
ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)
# グラフを表示
plt.show()
各打者ごとの各球種、コース (ヒット打たれたものは×)
import matplotlib.pyplot as plt
# 対戦したバッター数を取得
unique_batters = sorted(df_660261['at_bat_number'].unique())
# サブプロットの行数と列数を設定
nrows = (len(unique_batters) + 1) // 2
ncols = 2
# サブプロットのサイズを設定
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)
# ストライクゾーン
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
# バッターごとにデータをグループ分け
grouped_by_batter = df_660261.groupby('at_bat_number')
# 対戦したバッターごとに散布図を作成
for i, batter in enumerate(unique_batters):
data_by_batter = grouped_by_batter.get_group(batter)
# バッターのサブプロットを取得
ax = axs[i // ncols, i % ncols]
# ストライクゾーンを表示
ax.fill(x, y, color='r', alpha=0.1)
# バッターのデータを球種でグループ分け
grouped_by_pitch_type = data_by_batter.groupby('pitch_type')
# 各球種ごとに散布図を作成
for pitch_type, data in grouped_by_pitch_type:
ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type)
# ヒットを打たれたデータをプロット
hit_data = data[data['events'].isin(['single', 'double', 'triple', 'home_run'])]
if not hit_data.empty:
ax.scatter(hit_data['plate_x'], hit_data['plate_z'], marker='x', s=100, label=f'Hit ({pitch_type})')
# サブプロットのタイトルを設定
ax.set_title(f'Batter {i+1}')
# X 軸と Y 軸の範囲を設定
ax.set_xlim(-3, 3)
ax.set_ylim(-2, 6)
# X 軸と Y 軸のラベルを設定
ax.set_xlabel('Plate X')
ax.set_ylabel('Plate Z')
# 凡例を表示
ax.legend()
# 目盛り線を表示
ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)
# グラフを表示
plt.show()