【Pandas】データフレームでgroup byを使った集約・集計

Pandasでは様々なデータを加工、整形することができますが、その中の機能としてある条件でデータを集計することができます。

今回はPandasの集計関数であるgroupbyを用いてデータを集約・集計する方法を紹介します。

使用するデータ

今回はMicrosoftの株価データを使います。集計しやすいように、予め日付データを年月に分割しておきます。

import pandas as pd 

df = pd.read_csv("input/Microsoft_Stock.csv")

#Date型へ変換
df["Date"] = pd.to_datetime(df["Date"])

# Year列とMonth列を作成
df["Year"] = df["Date"].dt.year
df["Month"] = df["Date"].dt.month
df = pd.read_csv("input/Microsoft_Stock.csv")

今回は、2015/4/1 – 2021/3/31の期間で1日おきの株価データ(計1511件)です。

シンプルなgroupby

単一項目で集約

まずは最もシンプルな方法で集約します。例えば、年ごとの平均値を算出したい場合、”Year”列を用いて以下のようにします。

#単一項目でのGroupBy
df_agg = df.groupby("Year").mean()
df_agg = df.groupby("Year").mean()

年度ごとに集計されていることがわかります。集約に用いた項目(この場合は”Year”)はインデックスに割り当てられます。

gropubyをすると、集約できない文字列の属性等は除外されます。今回”Month”は数値型なので集計できてしまっていますが、実際は不要なので後続処理等で除外することになります。

複数項目で集約

上記データを年月で集約したい場合、”Year”、”Month”の2項目で集約することになります。その場合は、groupby()で渡す属性を配列で指定します。

#複数項目でのGroupBy
df_agg2 = df.groupby(["Year", "Month"]).mean()
df_agg2 = df.groupby(["Year", "Month"]).mean()

集約に用いた”Year”、”Month”はマルチインデックスとして割り当てられます。

集計関数について

集計は平均(mean)だけでなく、一般的な集約関数は一通り使うことができます。

#様々な集計関数を適用可能
df_agg_sum = df.groupby("Year").sum()
df_agg_max = df.groupby("Year").max()
df_agg_min = df.groupby("Year").min()

グループラベルをインデックスに指定しない場合

集約に用いた項目(グループラベル)は、デフォルトでは集約後インデックスに割り当てられますが、as_index=Falseとすることで、元の列として残しておくことができます。

#グループのラベルをインデックスにしない場合
df_agg_no_index = df.groupby("Year", as_index=False).mean()
df_agg_no_index = df.groupby("Year", as_index=False).mean()

やや手の込んだgroupby

複数の集約結果を得たい場合

集約したのち、平均と総和両方を得たいという場合に、groupbyを2度実行するのは非効率です。その場合は、groupby()の後でagg()を追加します。サンプルを見たほうが早いので、以下に示します。以下は、合計値と集約件数を取得する場合です。

※ただしこれはPandasのバージョンが1.x以降の場合のみですので、ご注意ください

#複数の集約結果をまとめて取得したい場合(下記はpandas v1以降対応のフォーマット)
df_agg3 = df.groupby("Year").agg(["sum", "count"])
df_agg3 = df.groupby("Year").agg(["sum", "count"])

実行結果はマルチカラムの形で返されます。

関数を使った処理

集計値を計算した値(例:最大から最小を引いた値)を求めたい場合などでは、agg()を用いて関数適用することができます。

lambda関数を用いた処理

集約した後、lambda関数で最大値から最小値を引いた値を求めてみます。

#lambdaを使った処理も可能
df_agg4 = df.groupby("Year").agg(lambda x: max(x) - min(x))
df_agg4 = df.groupby("Year").agg(lambda x: max(x) - min(x))

python関数を用いる場合

通常の関数を呼び出して処理することもできます。

#関数を使うこともできる
def sample(x):
    return max(x) - min(x)

df_agg5 = df.groupby("Year").agg(sample)
df_agg5 = df.groupby("Year").agg(sample)

統計量のプロット

集約した結果を、グラフで表現することもできます。棒グラフの場合は以下のようにします。

#グループごとの統計量をプロットする(棒グラフ)
#Volumeは値が大きすぎるため除外
ax = df.drop("Volume", axis=1).groupby("Year").mean().plot(rot=0)
fig = ax.get_figure()

【参考】
#折れ線グラフの場合
ax = df.drop("Volume", axis=1).groupby("Year").mean().plot(rot=0)
fig = ax.get_figure()
ax = df.drop("Volume", axis=1).groupby("Year").mean().plot(rot=0)fig = ax.get_figure()

Pythonでデータサイエンスするなら

Pythonでデータサイエンスをするなら、以下の書籍がおすすめです。Pandas、matplotlib、Numpy、scikit-learnといったデータサイエンスに必要なライブラリを、体系立てて一通り学ぶことができます。

ややお値段高めですが、これ1冊で十分という内容・ボリュームなので、損はしないと思います^^

初学者の方にはこちらもオススメです^^

まとめ

Pandasのgroupbyを使った集約・集計の方法を紹介しました。単純な集約(平均等)だけでなく、関数を用いたやや複雑な処理も可能なので、是非実践してみてください。

ではでは👋