【Python入門】野球データを使ってPandasの基本操作を習得しよう

【Python入門】野球データを使ってPandas基本操作を習得しよう Python

皆さん、こんにちは!

この記事では、私が集計(加工)した野球関連のデータを使って、Pythonを使っていくのに必須のライブラリであるPandasの基本操作を学習します。

朱莉
楽しみながら勉強していきましょう!

なお、Pandasのより詳細な使い方は別の記事で扱う予定です。

この記事で扱うPandasのコマンドは以下の通りです。

Contents

サンプルデータ

今回私のコードで使っているCSVファイルです。

NPBの2008年から2021年までのシーズンデータが入っており、野球好きの方であれば楽しくPythonを始められると思い、ダウンロード可能な状態としています。

皆さんもぜひ使ってみてください!

学習のため、一部のデータを欠損させています。
正確なデータではないことご注意ください。

また、データの取得方法に興味がある方は、下記の記事もおすすめです。

Pythonを使ったスクレイピングについて扱っています。

【プロ野球スクレイピング】年次データを抽出しExcelに出力 全選手、全年のデータを1つのファイルにまとめる

データの読み込み・書き込み、表示

Pandasを使う際に最も初めに行うのが、データの読み込み、書き込み、表示です。

冒頭のCSVファイルを手元にダウンロードし、演習を行うPythonファイルと同じディレクトリに置いてから、以下のコードを試してみてください。

事前準備

Pandasを使うためには、ライブラリをインポートする必要があります。

# pandas ライブラリをインポート
import pandas as pd

pd.read_csv()

CSVファイルを読み込むコマンドです。

pd.read_csv(ファイル名)が最低限あればCSVファイルを読み込めます。

残りの引数は、入力する必要はありませんが、ExcelでCSVファイルを読み込むのと同じように、区切り文字を選択したり、文字コードを指定することも可能です。

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
# 大きすぎるので略
df = df.iloc[:1000, 1:6]
df.head()

df.to_csv()

dataframeをCSV形式で出力するコマンドです。

こちらもread_csvと同じで、ファイル名のみが必須となります。

ただ、ファイルパスのみで保存してしまうと、以下の画像のように、インデックス(データフレームの通し番号)が入ってしまい使い勝手が悪いため、index = Falseとすることが多いです。

# 外部ファイルに吐き出す
df.to_csv("./test.csv")
# インデックスなしVer
df.to_csv("./test_1.csv", index=False)
# インデックスなし & 区切りが「;」
df.to_csv("./test_2.csv", index=False, sep=";")

df.head()

データフレームの先頭部分を表示するコマンドです。

Jupyter Notebookでは「df」のように、直打ちでも表示できてしまいますが、head()とすることで上から5行のみの表示になりスッキリします。

# 上から5行を表示(行数を指定することも可能)
df.head()

df.tail()

データフレームの末尾部分を表示するコマンドです。

こちらもheadと同じく、デフォルトだと5行、行数を指定することもできます。

# 下から指定行数を表示
df.tail(3)

データの情報を表示する

df.info()

データフレームの情報を表示するコマンドです。

以下の通り、行数や列数、各列にNullがあるか、データ型は何かなどを表示してくれます。

# データフレームの基本情報を表示
df.info()

df.describe()

データフレームの基本統計量を表示するコマンドです。

以下の通り、数値データを扱う列ごとに、行数や、平均値、標準偏差、最大値、最小値、四分位数が表示されます。

# データフレームの統計量を表示
df.describe()

df.columns

データフレームの列名をリスト形式で表示するコマンドです。

test = df.columns のようにすることで、列名をリスト形式で保持することも可能です。

# 列名を出力
df.columns

df.index

データフレームの行数を表示するコマンドです。

(あまり使いません)

# 行に関する情報(インデックス数)
df.index

df.dtypes

データフレームの各列のデータ型を表示するコマンドです。

(あまり使いません、df.info()でOKです)

# データフレームの各列の型
df.dtypes

df.shape

データフレームの行数と列数を表示するコマンドです。

# (行数, 列数)
df.shape

len(df)

Pandasではありませんが、データフレームの行数を取得するのによく使います。

len_ = len(df)として、for i in range(len_):とすれば簡単にデータフレームの長さ分ループさせることが可能です。

# 行数
len(df)

df.sum(axis=1)

データフレームを行単位で合計するコマンドです。

axis = 0 とすることで、列単位の合計になります。

df.sum(axis=1)

df.max()

データフレームの最大値を出力するコマンドです。

df.sum()と同じく、axis = 0 (または無記入)で列単位の最大値、axis = 1 で行単位の最大値です。

df.max()

df.mean()

データフレームの平均値を出力するコマンドです。

df.sum()と同じく、axis = 0 (または無記入)で列単位の平均値、axis = 1 で行単位の平均値です。

# 各列の平均値
df.mean()

セル・行・列の取得

df.loc[行番号,列名]

データフレームの要素を行番号と列名で指定するコマンドです。

loc はロケーションの略で、[ ]の第一引数を行番号(インデックス)、第二引数を列名(カラム)で取ります。

こちらの方が視覚的にデータを取れるのではないでしょうか。

# loc[行名, 列名]
df.loc[0,"選手名"]

行番号と、列名はリスト形式で選択可能です。

df.loc[[150,151], ["選手名", "打率"]]

df.iloc[行番号,列番号]

データフレームの要素を行番号と列番号で指定するコマンドです。

iloc はインデックスロケーションの略で、[ ]の第一引数を行番号(インデックス)、第二引数を列番号で取ります。

df.iloc[[0,1],[0,1]]

複数行や複数列を取りたい場合、こちらはリストを入れ子にするのではなく、[行,列]で書きます。

「0:2」と記述することで0番から2番までの範囲指定も可能です。

df.iloc[0:2,0:2]

ちなみに0番であれば、明示的に記述する必要はありません。

「:2」と記述することで0番から2番までの範囲指定も可能です。

df.iloc[:10, :10]

df[列名]

データフレームを列単位で取得するコマンドです。

こちらもリスト形式で複数列に対応しています。

df[["選手名","打率"]]

また1行のみの指定だと、Series形式での取得になります。

df["打率"]

その他、代入やTrue Faleseをつかった抽出など

ここでもう一度データを読み込みなおします。

データフレームを以下の例題がやり易いように絞り込んでおきます。

# 再度外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
# 大きすぎるので略
df = df.iloc[:10, 1:6]
df

データフレームのコピー

データフレームをコピーするコマンドです。

ここまで紹介したように、base = df

とするだけでも、コピーは出来ます。

base = df.copy()
base.head()

代入

データフレームに値を代入するコマンドです。

前述のlocやilocと組み合わせることで、行と列を指定して値を代入することが出来ます。

もちろん「:」にも対応しています。

# セルを指定して代入
df.loc[3, "チーム"] = "広島"
df

ノリ青木が広島に…!?

列指定の代入(新規作成)

データフレームに列を新規作成するコマンドです。

列指定で代入する際には、代入先のデータフレームの行数と、持っているデータの数が同一である必要があります。

※ただし df[“AS”] = “yes”としても、代入は可能です。この場合、以下のコードと全く同じ結果が得られます。

# 列を指定して代入
yes_list = ["yes"] * 10
print(yes_list)
df["AS"] = yes_list
df

列指定の代入(上書き)

データフレームに値を代入するコマンドです。

上から記述を書き換えられますが、新しく列を作った方が無難だと思います。

df["AS"] = "no"
df

データの削除

df.drop(columns=”列名”)

データフレームの列を削除するコマンドです。

列名を指定することで、当該列をデータフレームから除外します。

# 列を削除
df.drop(columns="チーム")

ちなみにaxis=1はデフォルトで入っているので不要です。

df.drop("チーム", axis=1)

df.drop(行番号)

データフレームから行指定でデータを削除するコマンドです。

特定の行だけ削除したい際に用います。

# 行の削除
df.drop(2)

del df[“列名”]

データフレームから列を削除するコマンドです。

先ほどの、dropとの違いは、delは不可逆的な削除なので、del コマンドを実行すると、元のデータフレームからも列が削除されます。

そのため、同じコードを2回実行しようとすると、「列名が無い」というエラーが出てしまうため注意が必要です。

個人的には、読み込みの次にdel文も書いておいて、データフレームをはじめから小さくする際などに使ったります。

del df["チーム"]
df

欠損値処理

ここでもう一度データを読み込みなおします。

データフレームを以下の例題がやり易いように絞り込んでおきます。

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
# 大きすぎるので略
df = df.iloc[:10, 1:6]
# 列の追加  
df["new_col"] = 1
df

df.isnull()

データフレームの各要素で、NaN値か否かを確認するコマンドです。

NaNの場合にTrue、NaN以外はFalseです。

# 欠損セルの確認
df.isnull()

df.isnull().any()

データフレームの列単位で、NaN値含まれるか確認するコマンドです。

先ほどのf.isnull()では、視認性が悪かったですが、df.isnull().any()を用いることで、どの列にNaNがあるかを判定できます。

# 欠損値を含む列を確認
df.isnull().any()

df.isnull().any(axis=1)

データフレームの行単位で、NaN値含まれるか確認するコマンドです。

# 欠損行の確認
df.isnull().any(axis=1)

df[]の中に、先ほどのコマンドを入れ込むことで、NaNを含む行のみを表示させることが出来ます。

最終的に良く使うのはこのコードでしょう。

len()の中に入れれば、NaNを含む行数を把握することも可能です。

df[df.isnull().any(axis=1)]

df.dropna()

データフレームから、NaN値を含む行を削除するコマンドです。

前述のコードからNaN値がどれくらいあるのか把握できた後、当該行を一括で削除することができます。

# 欠損行の削除
df.dropna()

データフレームから、NaN値を含む列を削除するコマンドです。

# 欠損列の削除
df.dropna(axis=1)

df.ffill()

データフレームから、NaN値を1行手前の数字で置き換えるコマンドです。

※野球データにはふさわしくない埋め方でしょう。

# 欠損を埋める(フォワードフィル) 手前の数字で埋める
df.ffill()

df.bfill()

データフレームから、NaN値を1行後ろの数字で置き換えるコマンドです。

※野球データにはふさわしくない埋め方でしょう。

# 欠損を埋める(バックフィル) 後ろの数字で埋める
df.bfill()

df.interpolate()

データフレームから、NaN値を全後の値の線形補間で置き換えるコマンドです。

※野球データにはふさわしくない埋め方でしょう。

# 欠損を埋める(線形補完)
df.interpolate()

df.fillna(任意)

データフレームから、NaN値を任意の値で置き換えるコマンドです。

※野球データにはふさわしくない埋め方でしょう。

# 欠損を埋める(任意の値)
df.fillna(100) # ()の中に(df["age"].mean)など平均値で埋めることも可能

平均値などを計算して入れることも可能です。

# 欠損を埋める(任意の値)
df.fillna(df["打席数"].mean()) # ()の中にmean(df["age"].mean)など平均値で埋める

重複処理

df.duplicated()

データフレームから、行単位で重複を確認するコマンドです。

※今回のデータでは、各列の値が全て一致するものは無かったようです。

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
df = df.iloc[:1000, :7]

# 重複行の確認
df.duplicated()

df.drop_duplicates([“列名”,”列名”])

データフレームから、任意の列を選択し、重複を確認するコマンドです。

以下の行では、試合と打席数の2つの変数で重複を除いた行をピックしてくれます。

# 重複削除
df.drop_duplicates(["試合","打席数"])

列名操作やインデックス操作

df.columns = [“列名”, …..]

データフレームの列名を変更するコマンドです。

ただし、与えるリストと、元のデータフレームの列数が一致している必要があります。

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
df = df.iloc[:10, :5]

# 列名を変更する
df.columns = ["Rank", "Player_name", "Team_name", "Average", "Games"]
df

df.rename(columns={“変更前の列名”:”変更後の列名”})

データフレームの列名を一部のみ変更するコマンドです。

辞書型で、{変更前:変更後}のように記述することで任意の列名を操作できます。

df.rename(columns={"Rank":"Number"})

df.index = 変更後のインデックス

データフレームのインデックスを振りなおすコマンドです。

# インデックスの変更  
df.index = range(1,11)

df.reset_index()

データフレームのインデックスをリセットするコマンドです。

ただし、この方法だと、index列ができてしまい、列数などが変わってしまいます。

# インデックスの初期化 (ただし、index列ができてしまう)
df.reset_index()

df.reset_index(drop=True)

データフレームのインデックスをリセットするコマンドです。

drop = Trueとすることで、元のインデックスは削除して、置き換えるような処理を行ってくれます。

df.reset_index(drop=True)

集約処理

df.groupby(“列名”)

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
df = df.iloc[:1000, 1:6]
df.columns = ["Player_name", "Team_name", "Average", "Games","At_Bats"]

データフレームを列名でグルーピングするコマンドです。

ただし、下記の記述だけでは、不十分で、”どのように集計するか”を定義する必要があります。

df.groupby("Team_name")

df.groupby(“列名”).sum()

データフレームを列名でグルーピングするコマンドです。

末尾に.sum()を付けることで、Team_nameでグルーピング後、残りの列を合計するというような処理になります。

df.groupby("Team_name").sum()

グルーピングしたものを新しいデータフレームとして定義するには、reset_index()でインデックスを振りなおしてもらえればOKです。

# groupbyをデータフレームにする
df.groupby("Team_name").sum().reset_index()

グルーピングを複数列で行うことも可能です。

以下の例では、チーム名と試合数が同一な行ごとに再集計を行っています。(この例は不適切かもしれません。)

# 複数の変数でgroupby
df.groupby(["Team_name", "Games"]).max().reset_index()

ソート

df.sort_values(“列名”)

データフレームをソートするコマンドです。

デフォルトでは昇順です。(小さい値から大きくなる)

# 外部ファイルを読み込む
df = pd.read_csv("./stats_summary_na.csv", sep=",", encoding = "utf-8")
# 欠損行の削除
df = df.dropna()

# ソート  
df.sort_values("試合")

df.sort_values(“列名”, ascending=False)

データフレームをソートするコマンドです。

ascending=False とすることで、降順に変更可能です。

df.sort_values("試合", ascending=False)

df.sort_values([“列名1″,”列名2”], ascending=[False,True])

データフレームをソートするコマンドです。

複数列を指定することで、第1引数のソート→第2引数の順でソートすることも可能です。

df.sort_values(["試合","打率"], ascending=[False,True])

まとめ

以上、長丁場でしたが、Pandasの基本操作について扱いました。

野球データを使ったPandasのチュートリアルは、おそらく世界でこのサイトにしかないと思います。

教科書や学習サービスを使って挫折してきた方が少しでもPythonを使いこなせるようになっていただけると嬉しいです!

朱莉
皆さんも、自分の興味のあるデータでPythonに入門しましょう!

【プロ野球スクレイピング】年次データを抽出しExcelに出力 全選手、全年のデータを1つのファイルにまとめる