0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

大谷選手の打球分析・仮 (2022) - ヒット vs アウト

Posted at

以下のような解析を実行しました。

  1. ストライクゾーン内のヒットイベントとアウトイベントの分布をプロットしました。
  2. 大谷選手の打球位置(ヒットとアウトイベント)をプロットしました。
  3. 大谷選手の打球位置(ヒットとアウトイベント)を2つの別々のヒストグラムで表示しました。
  4. 打球位置を描画しました。
  5. ヒストグラムのビン幅を変更して、打球の分布を修正しました。

これにより、大谷選手のヒットイベントとアウトイベントの打球位置の違いを視覚的に比較することができました。また、プロットのカスタマイズを通じて、分析結果をより明確に示す方法を学びました。


データ取得

このコードは、Pythonで書かれており、pybaseballというライブラリを使って、大谷翔平選手の2022年のMLBのデータを取得しています。

!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]

打ったコースの確認

このコードは、大谷翔平選手の2022年の打球の位置(コース)を散布図で可視化しています。'plate_x' と 'plate_z' の列を使って、ストライクゾーン内の打球の位置を表しています。欠損値を削除した後、matplotlibライブラリを使って散布図を作成し、表示しています。

# 打ったコースの確認

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()


打ったコースの確認(イベントごと)

このコードは、大谷翔平選手の打球の位置をイベントタイプ(ヒットやアウト)ごとに色分けして散布図で表示しています。イベントタイプに基づいてデータを分割し、ヒットとアウトのデータをそれぞれ青と赤でプロットしています。さらに、ストライクゾーンを黒い点線で追加し、散布図に凡例を表示しています。

# イベントタイプに基づいてデータを分割
hits = df_ohtani[df_ohtani['events'].isin(['single', 'double', 'triple', 'home_run'])]
outs = df_ohtani[~df_ohtani['events'].isin(['single', 'double', 'triple', 'home_run'])]

# 散布図に色分けしてデータをプロット
plt.scatter(outs['plate_x'], outs['plate_z'], color='red', label='Outs')
plt.scatter(hits['plate_x'], hits['plate_z'], color='blue', label='Hits')

# ストライクゾーンを追加 (黒い点線の枠線)
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='black', linestyle='--', label='Strike Zone')

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

# 凡例を追加
plt.legend()

# 散布図を表示
plt.show()


打ったコースの確認(イベントごと)・罫線追加

このコードは、前回の散布図にグリッド線を追加しています。散布図を色分けし、ヒットとアウトのデータをそれぞれ青と赤でプロットし、ストライクゾーンを黒い点線で追加しています。さらに、X軸とY軸に点線のグリッド線を追加し、視認性を向上させています。凡例を表示し、散布図を描画しています。

# 散布図に色分けしてデータをプロット
fig, ax = plt.subplots()
ax.scatter(outs['plate_x'], outs['plate_z'], color='red', label='Outs')
ax.scatter(hits['plate_x'], hits['plate_z'], color='blue', label='Hits')

# ストライクゾーンを追加 (黒い点線の枠線)
x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]
ax.plot(x, y, color='black', linestyle='--', label='Strike Zone')

# X軸とY軸にラベルを追加
ax.set_xlabel('Plate X')
ax.set_ylabel('Plate Z')

# 点線に変更
ax.yaxis.grid(True, linestyle='--', linewidth=1.0)
ax.xaxis.grid(True, linestyle='--', linewidth=1.0)

# 凡例を追加
ax.legend()

# 散布図を表示
plt.show()


打ったコースを2Dヒストグラムで表示

このコードは、アウトとヒットのそれぞれの打球の位置を2Dヒストグラムで表示しています。seabornライブラリを使用して、アウトとヒットの打球の分布をカラーマップで示しています。アウトとヒットのヒストグラムを並べて表示し、それぞれのストライクゾーンも黒い点線で追加しています。このプロットにより、アウトとヒットのデータの違いを視覚的に比較できます。

import seaborn as sns

def plot_hit_vs_out(outs, hits):
    fig, axs = plt.subplots(1, 2, figsize=(20, 10), sharex=True, sharey=True)
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # ストライクゾーンの座標
    x = [-0.88, 0.88, 0.88, -0.88, -0.88]
    y = [1.51, 1.51, 3.4, 3.4, 1.51]

    sns.histplot(data=outs, x='plate_x', y='plate_z', cmap="coolwarm", cbar=True, ax=axs[0], binwidth=0.5)
    axs[0].plot(x, y, linestyle='--', color='black')
    axs[0].set_title('Outs')

    sns.histplot(data=hits, x='plate_x', y='plate_z', cmap="coolwarm", cbar=True, ax=axs[1], binwidth=0.5)
    axs[1].plot(x, y, linestyle='--', color='black')
    axs[1].set_title('Hits')

    plt.show()

plot_hit_vs_out(outs, hits)


打ったコースを2Dヒストグラムで表示(色を変更)

このコードは、先程のコードとほぼ同じで、アウトとヒットのそれぞれの打球の位置を2Dヒストグラムで表示しています。ただし、ヒットのヒストグラムのカラーマップが "coolwarm_r" に変更されています。これは、coolwarmカラーマップの反転版で、ヒットのデータの色分けを変更しています。アウトとヒットのヒストグラムを並べて表示し、それぞれのストライクゾーンも黒い点線で追加しています。このプロットにより、アウトとヒットのデータの違いを視覚的に比較できます。

import seaborn as sns

def plot_hit_vs_out(outs, hits):
    fig, axs = plt.subplots(1, 2, figsize=(20, 10), sharex=True, sharey=True)
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # ストライクゾーンの座標
    x = [-0.88, 0.88, 0.88, -0.88, -0.88]
    y = [1.51, 1.51, 3.4, 3.4, 1.51]

    sns.histplot(data=outs, x='plate_x', y='plate_z', cmap="coolwarm", cbar=True, ax=axs[0], binwidth=0.5)
    axs[0].plot(x, y, linestyle='--', color='black')
    axs[0].set_title('Outs')

    sns.histplot(data=hits, x='plate_x', y='plate_z', cmap="coolwarm_r", cbar=True, ax=axs[1], binwidth=0.5)
    axs[1].plot(x, y, linestyle='--', color='black')
    axs[1].set_title('Hits')

    plt.show()

plot_hit_vs_out(outs, hits)


打球の位置を表示

このコードでは、大谷選手の打球の位置をプロットしています。ヒットイベント(ホームラン、二塁打、三塁打、単打)の打球位置を赤色で、それ以外のイベントの打球位置を灰色で散布図に表示しています。また、X軸とY軸のラベルを設定し、Y軸を反転しています。

さらに、ファウルラインを黒い太線で描画しています。これにより、打球の位置とファウルラインの関係が視覚的にわかりやすくなります。

この散布図を通じて、大谷選手のヒットとそれ以外の打球がどのような分布をしているかを確認することができます。

import matplotlib.pyplot as plt

# Filter the data for batter 660271 (Shohei Ohtani)
df_ohtani = df[df['batter'] == 660271]

# Define the list of events considered as hits (excluding hit_by_pitch)
hit_events = ['home_run', 'double', 'triple', 'single']

# Filter the data for hit events and remove rows with missing values in 'hc_x' and 'hc_y'
df_ohtani_hits = df_ohtani[df_ohtani['events'].isin(hit_events)].dropna(subset=['hc_x', 'hc_y'])
plt.scatter(df_ohtani_hits['hc_x'], df_ohtani_hits['hc_y'], color='red')

# Filter the data for other events (not considered as hits) and remove rows with missing values in 'hc_x' and 'hc_y'
df_ohtani_others = df_ohtani[~df_ohtani['events'].isin(hit_events)].dropna(subset=['hc_x', 'hc_y'])
plt.scatter(df_ohtani_others['hc_x'], df_ohtani_others['hc_y'], color='gray')

plt.xlabel('X coordinate')
plt.ylabel('Y coordinate')
plt.gca().invert_yaxis()

# Draw the foul lines
plt.plot([125, 250], [210, 85], 'k-', lw=3)
plt.plot([125, 0], [210, 85], 'k-', lw=3)

plt.show()


打球の位置を2Dヒストグラムで表示

このコードでは、大谷選手の打球の位置をヒットイベント(ホームラン、二塁打、三塁打、単打)ごとにカウントし、2つのヒストグラムプロットを作成しています。左側のプロットはアウトイベント、右側のプロットはヒットイベントを示しています。それぞれのプロットで、打球のX座標とY座標を使用してヒストグラムを作成し、ビン幅は5に設定しています。

また、ファウルラインを描画するためのdraw_foul_lines関数を定義し、それぞれのプロットに適用しています。

この2つのヒストグラムプロットを比較することで、大谷選手のヒットイベントとアウトイベントの打球位置の違いを視覚的に確認することができます。

import seaborn as sns

def plot_hit_vs_out(outs, hits):
    fig, axs = plt.subplots(1, 2, figsize=(20, 10), sharex=True, sharey=True)
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # Draw the foul lines
    def draw_foul_lines(ax):
        ax.plot([125, 250], [210, 85], 'k-', lw=3)
        ax.plot([125, 0], [210, 85], 'k-', lw=3)

    sns.histplot(data=outs, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[0], binwidth=5)
    axs[0].set_title('Outs')
    axs[0].set_xlabel('X coordinate')
    axs[0].set_ylabel('Y coordinate')
    axs[0].invert_yaxis()
    draw_foul_lines(axs[0])

    sns.histplot(data=hits, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[1], binwidth=5)
    axs[1].set_title('Hits')
    axs[1].set_xlabel('X coordinate')
    axs[1].set_ylabel('Y coordinate')
    axs[1].invert_yaxis()
    draw_foul_lines(axs[1])

    plt.show()

plot_hit_vs_out(df_ohtani_others, df_ohtani_hits)


打球の位置を2Dヒストグラムで表示(Y軸を反転)

このコードでは、plot_hit_vs_out関数の冒頭において、outsおよびhitsデータフレームのhc_y列の値を反転させています(負の値に変換)。これにより、グラフ上でY座標を反転させることができます。

この変更により、グラフがより現実的なフィールドの表示になります。左側のプロットはアウトイベントを示し、右側のプロットはヒットイベントを示しています。それぞれのプロットで、打球のX座標とY座標を使用してヒストグラムを作成し、ビン幅は5に設定しています。

また、draw_foul_lines関数も変更されており、Y座標が反転したことに合わせて、ファウルラインの描画が修正されています。

この2つのヒストグラムプロットを比較することで、大谷選手のヒットイベントとアウトイベントの打球位置の違いを視覚的に確認することができます。

import seaborn as sns
import matplotlib.pyplot as plt

def plot_hit_vs_out(outs, hits):
    # Invert Y values
    outs['hc_y'] = -outs['hc_y']
    hits['hc_y'] = -hits['hc_y']

    fig, axs = plt.subplots(1, 2, figsize=(20, 10), sharex=True, sharey=True)
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # Draw the foul lines
    def draw_foul_lines(ax):
        ax.plot([125, 250], [-210, -85], 'k-', lw=3)
        ax.plot([125, 0], [-210, -85], 'k-', lw=3)

    sns.histplot(data=outs, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[0], binwidth=5)
    axs[0].set_title('Outs')
    axs[0].set_xlabel('X coordinate')
    axs[0].set_ylabel('Y coordinate')
    draw_foul_lines(axs[0])

    sns.histplot(data=hits, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[1], binwidth=5)
    axs[1].set_title('Hits')
    axs[1].set_xlabel('X coordinate')
    axs[1].set_ylabel('Y coordinate')
    draw_foul_lines(axs[1])

    plt.show()

plot_hit_vs_out(df_ohtani_others, df_ohtani_hits)


打球の位置を2Dヒストグラムで表示(Y軸を反転2)

コード実行時は、反対になったら再度実行をする

このコードでは、plot_hit_vs_out関数内でsns.histplotを呼び出す際に、ビン幅が10に設定されています。これにより、グラフ上のビンが以前よりも広くなり、打球の分布がより広範囲にわたって表示されます。

それ以外の部分は前回と同様で、左側のプロットがアウトイベントを、右側のプロットがヒットイベントを示しています。Y座標が反転され、ファウルラインも描画されています。

ビン幅が10になったことで、大谷選手のヒットイベントとアウトイベントの打球位置の違いを、より広範囲にわたって視覚的に比較することができます。

import seaborn as sns
import matplotlib.pyplot as plt

def plot_hit_vs_out(outs, hits):
    # Invert Y values
    outs['hc_y'] = -outs['hc_y']
    hits['hc_y'] = -hits['hc_y']

    fig, axs = plt.subplots(1, 2, figsize=(20, 10), sharex=True, sharey=True)
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # Draw the foul lines
    def draw_foul_lines(ax):
        ax.plot([125, 250], [-210, -85], 'k-', lw=3)
        ax.plot([125, 0], [-210, -85], 'k-', lw=3)

    sns.histplot(data=outs, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[0], binwidth=10)
    axs[0].set_title('Outs')
    axs[0].set_xlabel('X coordinate')
    axs[0].set_ylabel('Y coordinate')
    draw_foul_lines(axs[0])

    sns.histplot(data=hits, x='hc_x', y='hc_y', cmap="coolwarm", cbar=True, ax=axs[1], binwidth=10)
    axs[1].set_title('Hits')
    axs[1].set_xlabel('X coordinate')
    axs[1].set_ylabel('Y coordinate')
    draw_foul_lines(axs[1])

    plt.show()

plot_hit_vs_out(df_ohtani_others, df_ohtani_hits)


2023のシフトルール変更で、これがどうなるか、次回確認する

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?