Pandas
前回、matplotlibで積み上げの折れ線グラフを作成する方法(plt.stackplot)を紹介しました。

今回、Pandasのgroupbyでキーによるグルーピングをして統計値を算出する方法を紹介します。
まずPandasのデータフレームをこんな感じで準備してみました。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df)
実行結果
alphabet number data
0 a 3 200
1 b 2 300
2 c 1 400
3 c 2 500
4 b 1 600
5 a 3 700
6 b 1 800
7 c 2 900
8 a 3 1000
今回はこれを使って、groupbyを試していきます。
それでは始めていきましょう。
groupbyの使い方
groupbyを使うには「データフレーム.groupby(キー).計算の関数」とします。
つまり先ほどのデータフレームで「alphabet」でグルーピングをして、それぞれのグループの総計を算出するには「df.groupby(“alphabet”).sum()」とします。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df.groupby("alphabet").sum())
実行結果
number data
alphabet
a 9 1900
b 4 1700
c 5 1800
これでalphabetが「a」の時のnumberの総計とdataの総計、また同じく「b」の時のnumberの総計とdataの総計、「c」の時のnumberの総計とdataの総計が算出されます。
上記の例では総和「.sum()」を使っていますが、他に平均値「.mean()」、最大値「.max()」、最小値「.min()」、標準偏差「.std()」、データ数「.count()」、統計値のまとめ「.describe()」などが使用できます。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df.groupby("alphabet").sum())
print(df.groupby("alphabet").mean())
print(df.groupby("alphabet").max())
print(df.groupby("alphabet").min())
print(df.groupby("alphabet").std())
print(df.groupby("alphabet").count())
print(df.groupby("alphabet").describe())
実行結果
number data
alphabet
a 9 1900
b 4 1700
c 5 1800
number data
alphabet
a 3.000000 633.333333
b 1.333333 566.666667
c 1.666667 600.000000
number data
alphabet
a 3 1000
b 2 800
c 2 900
number data
alphabet
a 3 200
b 1 300
c 1 400
number data
alphabet
a 0.00000 404.145188
b 0.57735 251.661148
c 0.57735 264.575131
number data
alphabet
a 3 3
b 3 3
c 3 3
number data \
count mean std min 25% 50% 75% max count mean
alphabet
a 3.0 3.000000 0.00000 3.0 3.0 3.0 3.0 3.0 3.0 633.333333
b 3.0 1.333333 0.57735 1.0 1.0 1.0 1.5 2.0 3.0 566.666667
c 3.0 1.666667 0.57735 1.0 1.5 2.0 2.0 2.0 3.0 600.000000
std min 25% 50% 75% max
alphabet
a 404.145188 200.0 450.0 700.0 850.0 1000.0
b 251.661148 300.0 450.0 600.0 700.0 800.0
c 264.575131 400.0 450.0 500.0 700.0 900.0
ただし計算対象のデータがその関数で計算できない場合はエラーとなりますので注意してください。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df.groupby("number").sum())
print(df.groupby("number").mean())
実行結果
alphabet data
number
1 cbb 1800
2 bcc 1700
3 aaa 1900
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/core/groupby/groupby.py:1942, in GroupBy._agg_py_fallback(self, how, values, ndim, alt)
1941 try:
-> 1942 res_values = self._grouper.agg_series(ser, alt, preserve_dtype=True)
1943 except Exception as err:
(中略)
TypeError: agg function failed [how->mean,dtype->object]
複数の統計値を一度に算出
複数の統計値を一度に算出するには「.agg([統計値1, 統計値2, 統計値3…])」とします。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df.groupby("alphabet").agg(["sum", "max", "min", "mean"]))
実行結果
number data
sum max min mean sum max min mean
alphabet
a 9 3 3 3.000000 1900 1000 200 633.333333
b 4 2 1 1.333333 1700 800 300 566.666667
c 5 2 1 1.666667 1800 900 400 600.000000
groupby後のデータの中身
groupbyによりグルーピングした後のデータの中身を見てみましょう。
ただしgroupbyでグルーピングしたデータはオブジェクトとなっているため、そのままprint関数に渡しても中身は見えません。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(df.groupby("alphabet"))
実行結果
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x1173037f0>
そこで「*(アスタリスク)」を使ってアンパックします。
アスタリスクを使ったアンパックに関してはこちらの記事で紹介していますので良かったらどうぞ。

import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
print(*df.groupby("alphabet"))
実行結果
('a', alphabet number data
0 a 3 200
5 a 3 700
8 a 3 1000) ('b', alphabet number data
1 b 2 300
4 b 1 600
6 b 1 800) ('c', alphabet number data
2 c 1 400
3 c 2 500
7 c 2 900)
これによるとgroupbyでグルーピングした後はタプルとしてそれぞれのキー毎に分類され、各列のデータが保存されているのが分かります。
そのためインデックスを指定すればグルーピングしたキー(インデックス「0」) 、データフレーム(インデックス「1」)が得られます。
import pandas as pd
df = pd.DataFrame()
df["alphabet"] = ["a", "b", "c", "c", "b", "a", "b", "c", "a"]
df["number"] = [3, 2, 1, 2, 1, 3, 1, 2, 3]
df["data"] = [200, 300, 400, 500, 600, 700, 800, 900, 1000]
for data in df.groupby("alphabet"):
print(data[0])
print(data[1])
print(data[1]["number"])
実行結果
a
alphabet number data
0 a 3 200
5 a 3 700
8 a 3 1000
0 3
5 3
8 3
Name: number, dtype: int64
b
alphabet number data
1 b 2 300
4 b 1 600
6 b 1 800
1 2
4 1
6 1
Name: number, dtype: int64
c
alphabet number data
2 c 1 400
3 c 2 500
7 c 2 900
2 1
3 2
7 2
Name: number, dtype: int64
次回はNumPyでndarrayを分割するsplit、array_split、hsplit、vsplit、dsplitを紹介します。
ではでは今回はこんな感じで。
コメント