打者の得意コースを打球スピードから推測する(大谷選手・2022の結果で試しに実施)

打者の得意コースを打球スピードから推測する

大谷選手(2022の結果)で試しに実施

***

# データ

<pre><code>!pip install pybaseball
from pybaseball import statcast
import pandas as pd
df = statcast(start_dt='2022-03-30', end_dt='2022-12-31')
df_ohtani = df[df['batter'] == 660271]
</code></pre>

***

# 打ったコースの確認

<pre><code># 打ったコースの確認

import matplotlib.pyplot as plt

# create scatter plot using 'plate_x' and 'plate_z' columns
df_ohtani = df_ohtani.dropna(subset=['plate_x','plate_z'])
plt.scatter(df_ohtani['plate_x'], df_ohtani['plate_z'])

# add labels for x and y axis
plt.xlabel('Plate X')
plt.ylabel('Plate Z')

# show the plot
plt.show()
</code></pre>

![](https://pbs.twimg.com/media/FupfSALWYAcolZu?format=png\&name=small)

***

# 打ったコース・打球スピードを反映させる

<pre><code># 'plate_x'と'plate_z'の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['plate_x', 'plate_z', 'launch_speed'])

# 散布図を作成し、打球速度に応じて点の色を変える
plt.scatter(df_ohtani['plate_x'], df_ohtani['plate_z'], c=df_ohtani['launch_speed'], cmap='viridis')

# ストライクゾーンを追加 (赤い点線の枠線)
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
plt.plot(x, y, color='r', linestyle='--')

# カラーバーを追加
cbar = plt.colorbar()
cbar.set_label('Launch Speed (mph)')

# 軸ラベルを追加
plt.xlabel('Plate X')
plt.ylabel('Plate Z')

# プロットを表示
plt.show()
</code></pre>

![](https://pbs.twimg.com/media/FupfUGfWAAETI4i?format=png\&name=small)

***

# 打ったコース・打球スピードの速い方 & 遅い方

<pre><code># 'plate_x'と'plate_z'の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['plate_x', 'plate_z', 'launch_speed'])

# 打球速度の中央値を計算
median_launch_speed = df_ohtani['launch_speed'].median()

# 中央値を基準にデータを分割
df_ohtani_slow = df_ohtani[df_ohtani['launch_speed'] <= median_launch_speed]
df_ohtani_fast = df_ohtani[df_ohtani['launch_speed'] > median_launch_speed]

# 遅い打球のグラフを作成
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
sc_slow = plt.scatter(df_ohtani_slow['plate_x'], df_ohtani_slow['plate_z'], c=df_ohtani_slow['launch_speed'], cmap='cool')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Slow Launch Speed')
cbar_slow = plt.colorbar(sc_slow)
cbar_slow.set_label('Launch Speed (mph)')

# 速い打球のグラフを作成
plt.subplot(1, 2, 2)
sc_fast = plt.scatter(df_ohtani_fast['plate_x'], df_ohtani_fast['plate_z'], c=df_ohtani_fast['launch_speed'], cmap='hot')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Fast Launch Speed')
cbar_fast = plt.colorbar(sc_fast)
cbar_fast.set_label('Launch Speed (mph)')

# プロットを表示
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupfW9EWwAIsge7?format=png\&name=small)

***

# 上位・下位25% / 打球スピード

<pre><code># 打球速度の上位25%と下位25%を計算
quantile_25 = df_ohtani['launch_speed'].quantile(0.25)
quantile_75 = df_ohtani['launch_speed'].quantile(0.75)

# 上位25%と下位25%を基準にデータを分割
df_ohtani_low = df_ohtani[df_ohtani['launch_speed'] <= quantile_25]
df_ohtani_high = df_ohtani[df_ohtani['launch_speed'] > quantile_75]

# 下位25%の打球のグラフを作成
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
sc_low = plt.scatter(df_ohtani_low['plate_x'], df_ohtani_low['plate_z'], c=df_ohtani_low['launch_speed'], cmap='cool')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Low Launch Speed (Bottom 25%)')
plt.xlim(-2, 2)  # X軸の範囲を設定
plt.ylim(0.5, 4)   # Y軸の範囲を設定
cbar_low = plt.colorbar(sc_low)
cbar_low.set_label('Launch Speed (mph)')

# 上位25%の打球のグラフを作成
plt.subplot(1, 2, 2)
sc_high = plt.scatter(df_ohtani_high['plate_x'], df_ohtani_high['plate_z'], c=df_ohtani_high['launch_speed'], cmap='hot')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('High Launch Speed (Top 25%)')
plt.xlim(-2, 2)  # X軸の範囲を設定
plt.ylim(0.5, 4)   # Y軸の範囲を設定
cbar_high = plt.colorbar(sc_high)
cbar_high.set_label('Launch Speed (mph)')

# プロットを表示
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupfZMZXsAEFzMD?format=png\&name=900x900)

***

# 上位・下位10% / 打球スピード

<pre><code># 打球速度の上位10%と下位10%の閾値を計算
low_threshold = df_ohtani['launch_speed'].quantile(0.1)
high_threshold = df_ohtani['launch_speed'].quantile(0.9)

# 閾値を基準にデータを分割
df_ohtani_low = df_ohtani[df_ohtani['launch_speed'] <= low_threshold]
df_ohtani_high = df_ohtani[df_ohtani['launch_speed'] >= high_threshold]

# 下位10%の打球のグラフを作成
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
sc_low = plt.scatter(df_ohtani_low['plate_x'], df_ohtani_low['plate_z'], c=df_ohtani_low['launch_speed'], cmap='cool')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Low Launch Speed (Bottom 10%)')
plt.xlim(-2, 2)  # X軸の範囲を設定
plt.ylim(0.5, 4)   # Y軸の範囲を設定
cbar_low = plt.colorbar(sc_low)
cbar_low.set_label('Launch Speed (mph)')

# 上位10%の打球のグラフを作成
plt.subplot(1, 2, 2)
sc_high = plt.scatter(df_ohtani_high['plate_x'], df_ohtani_high['plate_z'], c=df_ohtani_high['launch_speed'], cmap='hot')
plt.plot(x, y, color='r', linestyle='--')
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('High Launch Speed (Top 10%)')
plt.xlim(-2, 2)  # X軸の範囲を設定
plt.ylim(0.5, 4)   # Y軸の範囲を設定
cbar_high = plt.colorbar(sc_high)
cbar_high.set_label('Launch Speed (mph)')

# プロットを表示
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupfbHgXwAEky0k?format=png\&name=900x900)

***

# Zoneというデータを確認1

<pre><code>unique_zones = df['zone'].unique()
print("Unique Zones:", unique_zones)
</code></pre>

結果

<pre><code>Unique Zones: <IntegerArray>
[14, 8, 12, 5, 13, 7, 11, 9, 4, 6, 1, 2, 3, <NA>]
Length: 14, dtype: Int64
</code></pre>

***

# Zoneというデータを確認2

<pre><code>import numpy as np

# 'zone', 'plate_x', 'plate_z'の欠損値を削除
df = df.dropna(subset=['zone', 'plate_x', 'plate_z'])

# ゾーンごとに色を定義
zone_colors = {
    1: 'red',
    2: 'orange',
    3: 'yellow',
    4: 'green',
    5: 'blue',
    6: 'indigo',
    7: 'purple',
    8: 'pink',
    9: 'brown',
    11: 'gray',
    12: 'cyan',
    13: 'olive',
    14: 'lime'
}

plt.figure(figsize=(6, 6))

# ゾーンごとにデータをプロット
for zone, color in zone_colors.items():
    df_zone = df[df['zone'] == zone]
    plt.scatter(df_zone['plate_x'], df_zone['plate_z'], color=color, label=f'Zone {zone}', alpha=0.1)

# ストライクゾーンをプロット
plt.plot(x, y, color='r', linestyle='--')

# 軸の範囲とラベルを設定
plt.xlim(-2, 2)
plt.ylim(0.5, 4)
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Pitches by Zone')

# プロットを表示
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupfdjjXsAEfnWt?format=png\&name=small)

***

# Zoneというデータを確認3

<pre><code>import numpy as np

# 'zone', 'plate_x', 'plate_z'の欠損値を削除
df = df.dropna(subset=['zone', 'plate_x', 'plate_z'])

# ゾーンごとに色を定義
zone_colors = {
    1: 'red',
    2: 'orange',
    3: 'yellow',
    4: 'green',
    5: 'blue',
    6: 'indigo',
    7: 'purple',
    8: 'pink',
    9: 'brown'
}

plt.figure(figsize=(6, 6))

# ゾーンごとにデータをプロット
for zone, color in zone_colors.items():
    df_zone = df[df['zone'] == zone]
    plt.scatter(df_zone['plate_x'], df_zone['plate_z'], color=color, label=f'Zone {zone}', alpha=0.1)

# ストライクゾーンをプロット
plt.plot(x, y, color='r', linestyle='--')

# 軸の範囲とラベルを設定
plt.xlim(-2, 2)
plt.ylim(0.5, 4)
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Pitches by Zone')

# プロットを表示
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupffrGWIAoTBDp?format=png\&name=small)

***

# Zoneというデータを確認4

<pre><code>import numpy as np

# 'zone', 'plate_x', 'plate_z'の欠損値を削除
df = df.dropna(subset=['zone', 'plate_x', 'plate_z'])

# ゾーンごとに色を定義
zone_colors = {
    1: 'red',
    2: 'orange',
    3: 'yellow',
    4: 'green',
    5: 'blue',
    6: 'indigo',
    7: 'purple',
    8: 'pink',
    9: 'brown'
}

plt.figure(figsize=(15, 15))

# ゾーンごとにデータをプロット
for zone, color in zone_colors.items():
    df_zone = df[df['zone'] == zone]
    
    # サブプロットの作成
    plt.subplot(3, 3, zone)
    plt.scatter(df_zone['plate_x'], df_zone['plate_z'], color=color, label=f'Zone {zone}', alpha=0.1)

    # ストライクゾーンをプロット
    plt.plot(x, y, color='r', linestyle='--')

    # 軸の範囲とラベルを設定
    plt.xlim(-2, 2)
    plt.ylim(0.5, 4)
    plt.xlabel('Plate X')
    plt.ylabel('Plate Z')
    plt.title(f'Pitches in Zone {zone}')

# プロットを表示
plt.tight_layout()
plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupfiG-XoAUDO6U?format=png\&name=large)

***

# Zone別の打球速度(大谷さん) / Boxplot

<pre><code>import seaborn as sns

# 大谷選手のデータを抽出
df_ohtani = df[df['batter'] == 660271]

# 'zone'と'launch_speed'の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['zone', 'launch_speed'])

plt.figure(figsize=(12, 6))
sns.boxplot(x='zone', y='launch_speed', data=df_ohtani, palette='coolwarm')

# 各ゾーンの平均値を計算し、プロット
zone_mean = df_ohtani.groupby('zone')['launch_speed'].mean()

# ゾーンインデックスと実際のゾーン番号の対応関係
zone_order = sns.boxplot(x='zone', y='launch_speed', data=df_ohtani, palette='coolwarm').get_xticks()

for idx, mean in zip(zone_order, zone_mean):
    plt.text(idx, mean + 0.5, f'{mean:.2f}', fontsize=10, color='black', ha='center')

plt.xlabel('Zone')
plt.ylabel('Launch Speed (mph)')
plt.title('Ohtani\'s Launch Speed by Zone')

plt.show()

</code></pre>

![](https://pbs.twimg.com/media/Fupfkl0WYAMVE4r?format=png\&name=small)

***

# Zone別の打球速度(大谷さん)

<pre><code>import numpy as np
import pandas as pd

# 大谷選手のデータを抽出
df_ohtani = df[df['batter'] == 660271]

# 'zone'と'launch_speed'の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['zone', 'launch_speed'])

# 各ゾーンの平均値を計算
zone_mean = df_ohtani.groupby('zone')['launch_speed'].mean()

# ゾーンと打球スピードのマッピングを作成
zone_speed_mapping = {int(zone): round(speed, 2) for zone, speed in zip(zone_mean.index, zone_mean.values)}

# 3x3の配列にゾーンの平均打球スピードを配置
zone_speed_matrix = np.zeros((3, 3))

for i in range(3):
    for j in range(3):
        zone = i * 3 + j + 1
        zone_speed_matrix[i, j] = zone_speed_mapping[zone]

# データフレームに変換
zone_speed_df = pd.DataFrame(zone_speed_matrix, columns=['Zone 1', 'Zone 2', 'Zone 3'], index=['Row 1', 'Row 2', 'Row 3'])
zone_speed_df

</code></pre>

![](https://pbs.twimg.com/media/Fupfo5jXwAEMy-m?format=png\&name=360x360)

***

# Zone別の打球速度(大谷さん)・捕手側からの視点

インコース高め、アウトコース低め　が苦手気味？

<pre><code>fig, ax = plt.subplots(figsize=(10, 6))

# X軸の範囲とY軸の範囲を設定
plt.xlim(-2, 2)
plt.ylim(0.5, 4)

# ストライクゾーンをプロット
plt.plot(x, y, color='r', linestyle='--')

# ストライクゾーン内を9分割
ax.set_xticks([-0.88, 0, 0.88], minor=False)
ax.set_yticks([1.51, 2.455, 3.4], minor=False)
ax.yaxis.grid(True, linestyle='-', linewidth=1.0)
ax.xaxis.grid(True, linestyle='-', linewidth=1.0)

# 各ゾーンに平均打球スピードを配置
for i in range(3):
    for j in range(3):
        zone = (2 - i) * 3 + j + 1
        if zone in zone_speed_mapping:
            speed = zone_speed_mapping[zone]
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}\n{speed} mph", fontsize=12, ha='center', va='center')
        else:
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}", fontsize=12, ha='center', va='center')

# 軸のラベルを設定
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Average Launch Speed by Zone')

plt.show()

</code></pre>

![](https://pbs.twimg.com/media/Fupfrd5WAAEJYP7?format=png\&name=900x900)

***

# Zone別の打球速度(大谷さん)・色分け

<pre><code>import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

fig, ax = plt.subplots(figsize=(10, 6))

# X軸の範囲とY軸の範囲を設定
plt.xlim(-2, 2)
plt.ylim(0.5, 4)

# ストライクゾーンをプロット（alphaを0.3に設定）
ax.plot(x, y, color='black', linestyle='--', alpha=0.3)

# ストライクゾーン内を9分割
ax.set_xticks([-0.88, 0, 0.88], minor=False)
ax.set_yticks([1.51, 2.455, 3.4], minor=False)
# 点線に変更
ax.yaxis.grid(True, linestyle='--', linewidth=1.0)
ax.xaxis.grid(True, linestyle='--', linewidth=1.0)

# カラーマップを作成 (赤色: 高速, 青色: 低速)
colors = ['blue', 'red']
cmap = LinearSegmentedColormap.from_list('launch_speed', colors, N=100)
speeds = [v for _, v in zone_speed_mapping.items()]
norm = plt.Normalize(min(speeds), max(speeds))

# 各ゾーンに平均打球スピードを配置し、色を付ける
for i in range(3):
    for j in range(3):
        zone = (2 - i) * 3 + j + 1
        if zone in zone_speed_mapping:
            speed = zone_speed_mapping[zone]
            color = cmap(norm(speed))
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}\n{speed} mph", fontsize=12, ha='center', va='center', color=color)
        else:
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}", fontsize=12, ha='center', va='center')

# 軸のラベルを設定
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Average Launch Speed by Zone')

plt.show()

</code></pre>

![](https://pbs.twimg.com/media/FupftXGWcAEcaHe?format=png\&name=small)

***

# 各ゾーンの打率も計算してみる

<pre><code>import pandas as pd

# 大谷選手のデータを抽出
df_ohtani = df[df['batter'] == 660271]

# 'zone' および 'events' の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['zone', 'events'])

# ヒットとなるイベントをカウント
hit_events = ['single', 'double', 'triple', 'home_run']
df_ohtani['is_hit'] = df_ohtani['events'].apply(lambda x: x in hit_events)

# ゾーンごとの打席数とヒット数を集計
zone_counts = df_ohtani.groupby('zone')['events'].count()
zone_hits = df_ohtani.groupby('zone')['is_hit'].sum()

# 各ゾーンでの打率を計算
zone_batting_averages = zone_hits / zone_counts

# ゾーンと打率のマッピングを作成
zone_batting_mapping = {int(zone): round(ba, 3) for zone, ba in zip(zone_batting_averages.index, zone_batting_averages.values)}

print("Zone batting averages:", zone_batting_mapping)

</code></pre>

結果

<pre><code>Zone batting averages: {1: 0.286, 2: 0.571, 3: 0.318, 4: 0.246, 5: 0.352, 6: 0.385, 7: 0.208, 8: 0.309, 9: 0.286, 11: 0.089, 12: 0.125, 13: 0.13, 14: 0.13}
</code></pre>

***

# 除外すべきイベントを定義

<pre><code>import pandas as pd

# 大谷選手のデータを抽出
df_ohtani = df[df['batter'] == 660271]

# 'zone' および 'events' の欠損値を削除
df_ohtani = df_ohtani.dropna(subset=['zone', 'events'])

# 除外すべきイベントを定義
exclude_events = ['walk', 'hit_by_pitch', 'sac_fly', 'sac_bunt', 'sac_fly_double_play', 'sac_bunt_double_play', 'catcher_interf', 'wild_pitch', 'game_advisory', 'pickoff_3b', 'caught_stealing_3b', 'pickoff_caught_stealing_2b', 'caught_stealing_home', 'sac_fly_double_play', 'wild_pitch', 'pickoff_1b', 'pickoff_caught_stealing_home', 'pickoff_caught_stealing_3b', 'pickoff_2b', 'caught_stealing_2b', 'other_out']

# 除外イベントを除外したデータフレームを作成
df_ohtani_filtered = df_ohtani[~df_ohtani['events'].isin(exclude_events)].copy()

# ヒットとなるイベントをカウント
hit_events = ['single', 'double', 'triple', 'home_run']
df_ohtani_filtered.loc[:, 'is_hit'] = df_ohtani_filtered['events'].apply(lambda x: x in hit_events)


# ゾーンごとの打席数とヒット数を集計
zone_counts = df_ohtani_filtered.groupby('zone')['events'].count()
zone_hits = df_ohtani_filtered.groupby('zone')['is_hit'].sum()

# 各ゾーンでの打率を計算
zone_batting_averages = zone_hits / zone_counts

# ゾーンと打率のマッピングを作成
zone_batting_mapping = {int(zone): round(ba, 3) for zone, ba in zip(zone_batting_averages.index, zone_batting_averages.values)}

print("Zone batting averages:", zone_batting_mapping)

</code></pre>

結果

<pre><code>Zone batting averages: {1: 0.296, 2: 0.571, 3: 0.333, 4: 0.246, 5: 0.357, 6: 0.392, 7: 0.217, 8: 0.309, 9: 0.308, 11: 0.148, 12: 0.161, 13: 0.159, 14: 0.179}
</code></pre>

***

# Zone別の打率(大谷さん)・色分け

アウトコース低めは、打率も低め

<pre><code>import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

fig, ax = plt.subplots(figsize=(10, 6))

# X軸の範囲とY軸の範囲を設定
plt.xlim(-2, 2)
plt.ylim(0.5, 4)

# ストライクゾーンをプロット（alphaを0.3に設定）
ax.plot(x, y, color='black', linestyle='--', alpha=0.3)


# ストライクゾーン内を9分割
ax.set_xticks([-0.88, 0, 0.88], minor=False)
ax.set_yticks([1.51, 2.455, 3.4], minor=False)
# 点線に変更
ax.yaxis.grid(True, linestyle='--', linewidth=1.0)
ax.xaxis.grid(True, linestyle='--', linewidth=1.0)

# カラーマップを作成 (赤色: 高打率, 青色: 低打率)
colors = ['blue', 'red']
cmap = LinearSegmentedColormap.from_list('batting_average', colors, N=100)
batting_averages = [v for _, v in zone_batting_mapping.items()]
norm = plt.Normalize(min(batting_averages), max(batting_averages))

# 各ゾーンに打率を配置し、色を付ける
for i in range(3):
    for j in range(3):
        zone = (2 - i) * 3 + j + 1
        if zone in zone_batting_mapping:
            ba = zone_batting_mapping[zone]
            color = cmap(norm(ba))
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}\n{ba:.3f}", fontsize=12, ha='center', va='center', color=color)
        else:
            ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}", fontsize=12, ha='center', va='center')

# 軸のラベルを設定
plt.xlabel('Plate X')
plt.ylabel('Plate Z')
plt.title('Batting Average by Zone')

plt.show()

</code></pre>

![](https://pbs.twimg.com/media/Fupf7PqX0AIqiXt?format=png\&name=900x900)

***

# 各ゾーンごとにヒット、2塁打、3塁打、ホームランの個数を集計する

<pre><code># 各ゾーンごとにヒット、2塁打、3塁打、ホームランの個数を集計する
zone_single_counts = df_ohtani_filtered[df_ohtani_filtered['events'] == 'single'].groupby('zone')['events'].count()
zone_double_counts = df_ohtani_filtered[df_ohtani_filtered['events'] == 'double'].groupby('zone')['events'].count()
zone_triple_counts = df_ohtani_filtered[df_ohtani_filtered['events'] == 'triple'].groupby('zone')['events'].count()
zone_home_run_counts = df_ohtani_filtered[df_ohtani_filtered['events'] == 'home_run'].groupby('zone')['events'].count()

# ゾーンと各種イベントの個数のマッピングを作成
zone_single_mapping = {int(zone): count for zone, count in zip(zone_single_counts.index, zone_single_counts.values)}
zone_double_mapping = {int(zone): count for zone, count in zip(zone_double_counts.index, zone_double_counts.values)}
zone_triple_mapping = {int(zone): count for zone, count in zip(zone_triple_counts.index, zone_triple_counts.values)}
zone_home_run_mapping = {int(zone): count for zone, count in zip(zone_home_run_counts.index, zone_home_run_counts.values)}

print("Zone single counts:", zone_single_mapping)
print("Zone double counts:", zone_double_mapping)
print("Zone triple counts:", zone_triple_mapping)
print("Zone home run counts:", zone_home_run_mapping)

</code></pre>

結果

<pre><code>Zone single counts: {1: 6, 2: 5, 3: 3, 4: 8, 5: 11, 6: 9, 7: 9, 8: 9, 9: 5, 11: 3, 12: 4, 13: 12, 14: 6}
Zone double counts: {1: 2, 2: 4, 3: 1, 4: 6, 5: 3, 6: 6, 7: 1, 8: 3, 9: 1, 11: 1, 12: 1, 13: 1}
Zone triple counts: {2: 1, 3: 1, 6: 2, 7: 1, 8: 1}
Zone home run counts: {2: 6, 3: 2, 4: 2, 5: 11, 6: 3, 7: 4, 8: 4, 9: 2, 14: 1}
</code></pre>

***

# 各ゾーンごとにヒット、2塁打、3塁打、ホームランの個数を集計する(グラフ)

<pre><code>import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

fig, axs = plt.subplots(2, 2, figsize=(20, 12))

event_mappings = [zone_single_mapping, zone_double_mapping, zone_triple_mapping, zone_home_run_mapping]
event_titles = ['Singles by Zone', 'Doubles by Zone', 'Triples by Zone', 'Home Runs by Zone']
colors = ['blue', 'red']
cmap = LinearSegmentedColormap.from_list('count', colors, N=100)

for idx, (event_mapping, event_title) in enumerate(zip(event_mappings, event_titles)):
    ax = axs.flat[idx]

    # X軸の範囲とY軸の範囲を設定
    ax.set_xlim(-2, 2)
    ax.set_ylim(0.5, 4)

    # ストライクゾーンをプロット（alphaを0.3に設定）
    ax.plot(x, y, color='black', linestyle='--', alpha=0.3)

    # ストライクゾーン内を9分割
    ax.set_xticks([-0.88, 0, 0.88], minor=False)
    ax.set_yticks([1.51, 2.455, 3.4], minor=False)
    # 点線に変更
    ax.yaxis.grid(True, linestyle='--', linewidth=0.5)
    ax.xaxis.grid(True, linestyle='--', linewidth=0.5)

    counts = [v for _, v in event_mapping.items()]
    norm = plt.Normalize(min(counts), max(counts))

    # 各ゾーンにイベントの個数を配置し、色を付ける
    for i in range(3):
        for j in range(3):
            zone = (2 - i) * 3 + j + 1
            if zone in event_mapping:
                count = event_mapping[zone]
                color = cmap(norm(count))
                ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}\n{count}", fontsize=12, ha='center', va='center', color=color)
            else:
                ax.text(-0.88 + j * 0.88, 1.51 + i * 0.945, f"Zone {zone}", fontsize=12, ha='center', va='center')

    # 軸のラベルを設定
    ax.set_xlabel('Plate X')
    ax.set_ylabel('Plate Z')
    ax.set_title(event_title)

plt.show()

</code></pre>

![](https://pbs.twimg.com/media/Fupf\_\_wX0BIlX-z?format=png\&name=large)

***

いつかまとめたい