最終更新日:2021/8/21
.groupby()を使って、dfを特定の条件でグループ化して計算する方法を説明します。
例えば、各データがA, B, Cの何れかの値を必ず持っている場合、A, B, Cというくくりでグループ分けし、それぞれの合計を計算します。
【説明すること】
1. 簡単な計算
1つのカラムが対象の場合
和、平均、最小値、最大値など、簡単な計算は、関数が用意されているので、df.groupby()
を使って、 df.groupby(['clm0']).sum()['clm2']
と書きます。
この例は、’clm0’でグループ化し、’clm2’の和を集計する、という意味です。(対象が違う。)
複数のカラムが対象の場合
複数のカラムでグループ化したい場合は.goupby()
の引数にリストでカラム名を指定して、 df.groupby(['clm0','clm1']).sum()['clm2']
と書きます。
この例は、’clm0’を第一優先、’clm1’を第二優先でグループ化し、’clm2’の和を集計する、という意味です。
代表的な関数
代表的な関数は以下の通りです。
.sum()
: 和.mean()
: 平均 .min()
: 最小値.max()
: 最大値 .prod()
: 積(ExcelのPORDUCT()) .var(ddof=k)
: 分散 (ddofは不偏分散ならばk=1を指定します。つまり分母。).std(ddof=k)
: 標準偏差(ddofは不偏分散ならばk=1を指定します。つまり分母。)
更に関数を知りたい場合は、以下のpandasのページを参照してください(英語)
https://pandas.pydata.org/pandas-docs/stable/reference/groupby.html
サンプルコード
以下のcsvファイルを読み込んで例を挙げます。
【1つのカラムが対象の場合】
【複数のカラムが対象の場合】
【株価データの例】
以下のcsvファイルを読み込んで例を挙げます。
2. ラムダ関数を使った少し複雑な計算
少し複雑な計算は、.apply(lambda x: f(x))
で、ラムダ関数を使用して実行することができます。
例えば、(価格)×(数量)=(合計金額)を集計したい場合は、以下のように書きます。 df.groupby(['city','item']).apply(lambda x: (x['price'] * x['qty']).sum())
【合計金額の例】
【株価の例】
3. 一気に計算する場合
.agg()
を使えば、全てのカラムに対してまとめて計算することができます。
例えば、clm0, clm1をグループ化して、それらグループごとの和を集計したい場合は、以下のように書きます。 df.groupby(['clm0','clm1']).agg(['sum'])
ここで注意が必要なのが関数の指定方法です。
大きく分けて2つの方法があります。
(1) 組み込み関数を使う
この場合、ライブラリーをimportする必要はありません。
普通に関数の名前を書くだけです。但し、カッコ「()」は付きません。
例えば、和の場合、’sum’と書きます(”でくくる。カッコなし)。
「sum()」でも「sum」(”がない)でもありません。
(2) numpyを使う
numpyという数学計算用のライブラリーを使う場合は、numpyをimportして、np.cumprod
のようにカッコを付けないで書きます。
コードは、最初にimport numpy as np
と書くのを忘れないでください。
よく使うnumpyの関数は以下の通りです。
関数 | 計算の内容 |
np.sum | 総和 |
np.prod | 総乗 |
np.cumsum | 累積和 |
np.cumprod | 累積積 |
np.nansum | 総和 (欠損値は1として計算実行) |
np.nanprod | 総乗 (欠損値は1として計算実行) |
np.nancumsum | 累積和 (欠損値は1として計算実行) |
np.nancumprod | 累積積 (欠損値は1として計算実行) |
更に詳しく知りたい場合は、以下のpandasのサイトを参考にしてくだい(英語)。
https://pandas.pydata.org/pandas-docs/version/0.23/generated/pandas.core.groupby.DataFrameGroupBy.agg.html
numpyの例
numpyの関数を使ったコードの例を挙げます。
更に、以下のcsvファイルを読み込み、numpyの各関数の例を示します。
4. 結果をcsvに出力する
.groupby()
で計算した結果をcsvに出力したい事もあるでしょう。
例えば、データの数が多く、コードの正しさを検証する場合が考えられます。
この場合、結果を入れたdf_resultに対して、df_result.to_csv()
だけではうまくいきません。
以下のように、df.groupby()のオプションでas_index = False
を指定すれば、出力が可能です。
df_new = df.groupby(['clm0', 'clm1], as_index = False).sum()['clm2']
この理由は、後述する.groupby()
の出力のイメージ図をご覧頂くと、納得がいくはずです。
【csvに出力できない理由】
as_index = False
を指定しない場合、以下のようにcityカラムがExcelでいうセルの結合のようになっています。これでは、dfに必須のindex番号を振りようにも振れません。
結合したセルにデータを入力しても、1行でカウントされる状態です。
city | item |
qty |
Nagoya |
apple |
50 |
banana |
20 |
|
grape |
30 |
|
Osaka |
apple |
100 |
banana |
600 |
|
grape |
300 |
|
Tokyo |
apple |
1000 |
banana |
2000 |
|
grape |
7000 |
as_index = False
を指定すると、Excelでいうセルの結合が解除され、1行ずつに分類されます。これで、index番号が振れるようになるわけです。
index | city | item | qty |
0 | Naogya | apple | 50 |
1 | Naogya | banana | 20 |
2 | Naogya | grape | 30 |
3 | Osaka | apple | 100 |
4 | Osaka | banana | 600 |
5 | Osaka | grape | 300 |
6 | Tokyo | apple | 1000 |
7 | Tokyo | banana | 2000 |
8 | Tokyo | grape | 7000 |
これはあくまでイメージですが、基本的にデータは、1行ずつ完結する形になっていなければならない訳です。