LoginSignup
0
0

More than 1 year has passed since last update.

Python 動くグラフ (2021 MLB American League / Home Run 争い)

Last updated at Posted at 2023-03-05

前回、pybaseball / MLBデータ分析ライブラリ にて、MLBの触れるデータを確認した。

今回は試しに、2021年 MLB アメリカンリーグ 本塁打争いのデータを確認してみた。

まあ、以下のようなのが作ってみたかったのです。


備忘録として流れを記載


pybaseballライブラリを使ってMLBのStatcastデータを取得する。

!pip install pybaseball
from pybaseball import statcast
df = statcast(start_dt='2021-04-01', end_dt='2021-12-31')

Pythonを使う。pybaseballライブラリを使って、MLBのStatcastデータを取得する。

pip installコマンドを使ってpybaseballライブラリをインストール。

ライブラリがインストールされたら、statcast()関数を使って、指定した期間のStatcastデータを取得。この場合、2021年4月1日から2021年12月31日の期間のデータをリクエスト。この関数は、指定した期間のStatcastデータを含むPandasのデータフレームを返す。

注意することとして、pybaseballが提供するStatcastデータは、レギュラーシーズンのゲームのみを含む。プレーオフやオールスターゲームのデータは含まれない。

3月のデータがあったのでオープン戦の結果は入ってそう。


大谷のホームラン数で確認

player_hr = df[(df['batter'] == 660271) & (df['events'] == 'home_run')]
print(len(player_hr))

このコードでは、Pandasデータフレームdfから打者IDが660271で、イベントがホームランのデータを抽出している。それらのデータを含む新しいデータフレームplayer_hrが作成される。

ID 660271 は大谷です
https://baseballsavant.mlb.com/savant-player/shohei-ohtani-660271
URLにIDが載ってます

その後、len()関数を使ってplayer_hrデータフレームの行数(すなわち、ホームランの発生した試合数)をカウントしている。その結果をprint()関数を使って出力。

結果は、46

2021年 大谷のホームラン数と一致。OK


大谷のホームランをグラフ化

player_hr = df[(df['batter'] == 660271) & (df['events'] == 'home_run')]
player_hr_by_date = player_hr.groupby('game_date').size()

このコードでは、まずPandasデータフレームdfから、打者IDが660271で、イベントがホームランのデータを抽出。それらのデータを含む新しいデータフレームplayer_hrが作成される。

次に、groupby()メソッドを使って、player_hrデータフレームをゲーム日ごとにグループ化。size()関数を使って、各ゲーム日ごとの行数(すなわち、ホームランの発生した試合数)をカウント。その結果を、新しいデータフレームplayer_hr_by_dateに格納。

これで、ゲーム日ごとにホームランの発生した試合数が、新しいデータフレームplayer_hr_by_dateに格納される。

import matplotlib.pyplot as plt

plt.plot(player_hr_by_date.cumsum())
plt.show()

このコードでは、Matplotlibライブラリを使って、データフレームplayer_hr_by_dateのグラフを描画。

plot()関数を使ってデータフレームのデータを折れ線グラフとして描画。また、cumsum()関数を使って、各ゲーム日ごとのホームランの発生した試合数を累積和にしている。

最後に、show()関数を使って、グラフを表示。

このコードを実行すると、指定した期間内で、各ゲーム日ごとにホームランを打った試合数を累積和としたグラフが描画される。


選手を追加

2021年ホームラン数Top8に入った選手のデータを追加してみました。

ID Player
660271 Shohei Ohtani
665489 Vladimir Guerrero
521692 Salvador Pérez
543760 Marcus Semien
571745 Mitch Haniger
592450 Aaron Judge
664040 Brandon Lowe
621566 Matt Olson
# 選手のID 
player_ids = [660271, 665489, 521692, 543760, 571745, 592450, 664040, 621566]

# 選手ごとのホームラン数を日付ごとに集計 
player_hrs = {}
for player_id in player_ids:
  player_hr = df[(df['batter'] == player_id) & (df['events'] == 'home_run')]
  player_hrs[player_id] = player_hr.groupby('game_date').size()

このコードでは複数の選手のIDを含むリストplayer_idsを定義している。次にこのリストを使って選手ごとにホームランの発生した試合数を日付ごとに集計。

for文を使ってplayer_idsリストを一つずつ取り出している。取り出した選手IDを使って、Pandasデータフレームdfから打者ID、イベントがホームランのデータを抽出。それらのデータを含む新しいデータフレームを作成。

次に、groupby()メソッドを使ってこのデータフレームをゲーム日ごとにグループ化。そしてsize()関数を使って各ゲーム日ごとの行数(すなわち、ホームランの発生した試合数)をカウント。その結果を辞書player_hrsのキーが選手のID、値がゲーム日ごとのホームランの発生した試合数を持つSeriresオブジェクトとして格納。

実行すると辞書player_hrsには、各選手のゲーム日ごとのホームランの発生した試合数がSeriresオブジェクトとして格納。

import matplotlib.pyplot as plt

# プロットを重ねるため、プロットを初期化 
plt.clf()

# 選手ごとにプロット 
for player_id, player_hr in player_hrs.items():
  plt.plot(player_hr.cumsum())

plt.show()

このコードでは、Matplotlibライブラリを使って、複数の選手のゲーム日ごとのホームランの発生した試合数をプロットしている。

まずclf()関数を使ってプロットを初期化。これにより前回のプロットが重なることを防ぐ。

次に、for文を使って辞書player_hrsから選手のIDとその選手のゲーム日ごとのホームランの発生した試合数を取り出している。そして、plot()関数を使ってこのデータを折れ線グラフとして描画している。またcumsum()関数を使って各ゲーム日ごとのホームランの発生した試合数を累積和にして描画している。

最後にshow()関数を使ってプロットを表示。

このコードを実行すると、複数の選手のゲーム日ごとにホームランを打った試合数を累積和としたグラフが重ねて描画される。

グラフにレジェンドを追加するのは、以下です

plt.legend()


累積値のデータを作成

csvファイルは試しに実行しただけ。

import pandas as pd

# データフレームを作成
df_hrs = pd.DataFrame(player_hrs)

# df_hrs データフレームを累積値にする
df_hrs_cumsum = df_hrs.cumsum()

# CSV ファイルに保存
df_hrs_cumsum.to_csv('player_hrs_cumsum.csv', index=True)

このコードでは辞書player_hrsからPandasデータフレームを作成。辞書のキーがカラム名、値がデータとして、新しいデータフレームdf_hrsを作成。

次に、データフレームdf_hrsを累積値にして、新しいデータフレームdf_hrs_cumsumを作成。

最後にデータフレームdf_hrs_cumsumをCSVファイルplayer_hrs_cumsum.csvとして保存。引数index=Trueを指定することで、データフレームのインデックスも保存される。

このコードを実行すると、カラム名が選手のID、行名がゲーム日を表すインデックスを持つ、CSVファイルが作成される。各カラムには、その選手のゲーム日ごとにホームランを打った試合数を累積値として保存される。

import pandas as pd

# CSV ファイルを読み込む
df = pd.read_csv('player_hrs_cumsum.csv')

# データフレームを表示する
df

このコードでは、Pandasのread_csv()関数を使ってCSVファイルplayer_hrs_cumsum.csvを読み込んでいる。この関数はCSVファイルをPandasデータフレームとして読み込むことができる。

読み込んだデータフレームを行名がゲーム日を表すインデックスを持つ、カラム名が選手のIDを持つデータフレームとして、変数dfに格納。

最後に、変数dfを表示している。これにより、カラム名が選手のID、行名がゲーム日を表すインデックスを持つ、CSVファイルを読み込んだデータフレームが表示される。


NaNを0へ

df = df.fillna(0)

# データフレームを表示する 
df

このコードでは、Pandasのfillna()メソッドを使ってデータフレームdfのNaN(Not a Number)を指定した値で埋めている。

fillna()メソッドは、データフレームのNaNを任意の値で埋めることができるメソッド。引数に埋める値を指定できる。

このコードでは、fillna()メソッドを使ってデータフレームdfのNaNを0で埋めている。これによりデータフレームdf内に含まれるすべてのNaNが0で埋められる。

このコードを実行すると、データフレームdfのすべてのNaNが0で埋められる。


game_dateカラムを日付型に変換

する意味なかったかも、むしろ不要

df["game_date"] = pd.to_datetime(df["game_date"])
df.set_index("game_date", inplace=True)

このコードでは、Pandasのto_datetime()関数を使ってデータフレームdfのgame_dateカラムを日付型に変換している。

to_datetime()関数は、日付文字列やタイムスタンプを日付型のデータに変換することができる関数。引数に変換したい日付文字列やタイムスタンプを指定する。

このコードでは、to_datetime()関数を使ってデータフレームdfのgame_dateカラムを日付型に変換している。これによりgame_dateカラムは日付型のデータになる。

次に、Pandasのset_index()メソッドを使ってデータフレームdfのインデックスをgame_dateカラムに設定している。引数inplace=Trueを指定することでデータフレームを直接書き換えることができる。

このコードを実行するとデータフレームdfのgame_dateカラムが日付型に変換され、データフレームdfのインデックスがgame_dateカラムに設定される。

これにより、データフレームdfはゲーム日を表す日付型のインデックスを持つカラム名が選手のIDを持つデータフレームになる。


前日の値を引き継ぐようにした

4/1からでも良かったけど。過剰に行った

df_after_3_15 = df[df.index >= "2021-03-15"]

# 各列を取得する 
columns = df_after_3_15.columns

# 各列ごとに処理を行う 
for column in columns:
    values = df_after_3_15[column]
    for i in range(1, len(values)):
        if values[i] == 0:
            values[i] = values[i - 1]

# 変更したデータを、元のデータフレームに戻す 
df_after_3_15[column] = values

このコードでは、データフレームdfから2021年3月15日以降のデータを取り出して新しいデータフレームdf_after_3_15を作成している。

次に、データフレームdf_after_3_15の各カラムを取り出しそれぞれに対して処理を行っている。

処理は、各カラムのデータを取り出しそれを1つずつ繰り返し処理している。1番目のデータは何もしないが、2番目以降のデータは前のデータと同じ値に更新している。

これにより、2番目以降のデータが前のデータと同じ値に更新される。

最後に、変更したデータを元のデータフレームdf_after_3_15に戻している。

このコードを実行するとデータフレームdf_after_3_15の各カラムの2番目以降のデータが前のデータと同じ値に更新される。

print(df_after_3_15)


カラム名を変更

print(df_after_3_15.columns)

Index(['660271', '665489', '521692', '543760', '571745', '592450', '664040',
'621566'],
dtype='object')

print(df_after_3_15.columns)で、現在のカラム名を表示した

df_after_3_15.columns =  ['Shohei Ohtani', 'Vladimir Guerrero Jr.', 'Salvador Pérez', 'Marcus Semien', 'Mitch Haniger', 'Aaron Judge', 'Brandon Lowe', 'Matt Olson']

df_after_3_15.columnsに新しいカラム名のリストを代入することでカラム名を変更

print(df_after_3_15.columns)

Index(['Shohei Ohtani', 'Vladimir Guerrero Jr.', 'Salvador Pérez',
'Marcus Semien', 'Mitch Haniger', 'Aaron Judge', 'Brandon Lowe',
'Matt Olson'],
dtype='object')

これでOK


Bar Chart Race 作成

!pip install bar_chart_race

import pandas as pd
import bar_chart_race as bcr

bcr.bar_chart_race(df=df_after_3_15, n_bars=8)

追加確認

4/1に0追加

import numpy as np
import pandas as pd

# 全選手に0というデータを追加する 
new_row = np.zeros(8)

# データフレームに追加する 
df_after_3_15.loc['2021-04-01'] = new_row

# インデックスを日付に変換する 
df_after_3_15.index = pd.to_datetime(df_after_3_15.index)

# データフレームを昇順に並べ替える 
df_after_3_15.sort_index(inplace=True)

# 追加されたことを確認する 
print(df_after_3_15)

このコードは、すべての値が0に設定された新しい行をdf_after_3_15データフレームに追加する。新しい行はインデックス'2021-04-01'に追加される。

次に、pandasライブラリのto_datetime関数を使用して、データフレームのインデックスを日付型オブジェクトに変換。

最後に、sort_index関数を使用してデータフレームをインデックスの昇順で並び替え。inplaceパラメータがTrueに設定されているため、データフレームはインプレースで並び替えられ、元のデータフレームが修正される。

このコードを実行すると、df_after_3_15データフレームにはインデックス'2021-04-01'に新しい行が含まれ、インデックスの昇順で並び替えられる。


グラフ

import matplotlib.pyplot as plt

# 折れ線グラフを作成する 
plt.plot(df_after_3_15)

# グラフにレジェンドを追加する 
plt.legend(df_after_3_15.columns)

# グラフを表示する 
plt.show()

このコードは、matplotlib.pyplotライブラリのplot関数を使用して、df_after_3_15データフレームのデータを折れ線グラフで表示。

その後、legend関数を使用してデータフレームの列名をラベルとしてプロットに凡例を追加する。

最後に、show関数を使用してプロットを表示。

このコードを実行すると、df_after_3_15データフレームのデータを示す折れ線グラフと列名を示す凡例が表示される。


データ追加後、Bar Chat Race 反応しなかった。

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