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

なお、Pandasのより詳細な使い方は別の記事で扱う予定です。
この記事で扱うPandasのコマンドは以下の通りです。
Contents
サンプルデータ
今回私のコードで使っているCSVファイルです。
NPBの2008年から2021年までのシーズンデータが入っており、野球好きの方であれば楽しくPythonを始められると思い、ダウンロード可能な状態としています。
皆さんもぜひ使ってみてください!
正確なデータではないことご注意ください。
また、データの取得方法に興味がある方は、下記の記事もおすすめです。
Pythonを使ったスクレイピングについて扱っています。
データの読み込み・書き込み、表示
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を使いこなせるようになっていただけると嬉しいです!
