はじめに
書きたいことをタイトルで端的に表現できずに困った。 例として、バナナとミカンとイチゴの販売データを表現するDataFrameがあったとする。 そして、今回はイチゴが売れなかったので、販売データにはイチゴは含まれていないとする。
商品 数量 0 バナナ 1 1 ミカン 4 2 バナナ 3 3 バナナ 1 4 ミカン 6 5 ミカン 1 6 バナナ 4
このDataFrameを以下のように商品ごとに集計すると、
df = df.groupby('商品').sum() print(df)
出力結果は以下のようになる。
数量 商品 バナナ 9 ミカン 11
この表にはイチゴのデータがなく、レポートとして見たときには網羅性がなくてイマイチなので、改善してイチゴのデータ(販売数は0)も含めたい。
環境
$ python3 --version Python 3.10.12 $ poetry show | grep pandas pandas 2.2.1 Powerful data structures for data analysis, tim...
対処方法
groupby()の結果、商品がインデックスになる。 このインデックスをイチゴも含めて再構築すればよい。 具体的には、以下のようにする。
df = df.reindex(['バナナ', 'ミカン', 'イチゴ'], fill_value=0) print(df)
出力結果は以下のようになり、イチゴの行も含まれる。
数量 商品 バナナ 9 ミカン 11 イチゴ 0
reindex()
の引数にfill_value=0
を付与しない場合は、イチゴの数量は欠損値(NaN
)となる。
欠損値を細かく制御したい場合は、fill_value=0
を付与せずに、後でfillna()
等を実行して適切な値を埋めればよい。
マルチインデックスの場合はどうするか
以下に先程と似たような販売データを示すが、「店舗」という列を付け加えており、A店、B店、C店の3店舗あるとする。 商品は先程と同じくバナナ、ミカン、イチゴの3種類あるとする。
店舗 商品 数量 0 A店 バナナ 1 1 C店 ミカン 4 2 C店 バナナ 3 3 A店 バナナ 1 4 C店 ミカン 6 5 A店 ミカン 1 6 A店 イチゴ 4
このDataFrameを以下のように商品ごとに集計すると、
df = df.groupby(['店舗', '商品']).sum() print(df)
出力結果は以下のようになる。
数量 店舗 商品 A店 イチゴ 4 バナナ 2 ミカン 1 C店 バナナ 3 ミカン 10
C店にはイチゴのデータはなく、業績不振で商品がひとつも売れなかったB店のデータはまったくない。 そこで、以下のようにして、マルチインデックスを再構築する。
shops = ['A店', 'B店', 'C店'] products = ['バナナ', 'ミカン', 'イチゴ'] df = df.reindex(pd.MultiIndex.from_product([shops, products], names=['店舗', '商品']), fill_value=0) print(df)
出力結果は以下のように網羅性のある表になる。
数量 店舗 商品 A店 バナナ 2 ミカン 1 イチゴ 4 B店 バナナ 0 ミカン 0 イチゴ 0 C店 バナナ 3 ミカン 10 イチゴ 0
参考
付録A シングルインデックスのテストコード
import pandas as pd data = [ {'商品': 'バナナ', '数量': 1}, {'商品': 'ミカン', '数量': 4}, {'商品': 'バナナ', '数量': 3}, {'商品': 'バナナ', '数量': 1}, {'商品': 'ミカン', '数量': 6}, {'商品': 'ミカン', '数量': 1}, {'商品': 'バナナ', '数量': 4}, ] df = pd.DataFrame(data) print(df) df = df.groupby('商品').sum() print(df) df = df.reindex(['バナナ', 'ミカン', 'イチゴ'], fill_value=0) print(df)
付録B マルチインデックスのテストコード
import pandas as pd data = [ {'店舗': 'A店', '商品': 'バナナ', '数量': 1}, {'店舗': 'C店', '商品': 'ミカン', '数量': 4}, {'店舗': 'C店', '商品': 'バナナ', '数量': 3}, {'店舗': 'A店', '商品': 'バナナ', '数量': 1}, {'店舗': 'C店', '商品': 'ミカン', '数量': 6}, {'店舗': 'A店', '商品': 'ミカン', '数量': 1}, {'店舗': 'A店', '商品': 'イチゴ', '数量': 4}, ] df = pd.DataFrame(data) print(df) df = df.groupby(['店舗', '商品']).sum() print(df) shops = ['A店', 'B店', 'C店'] products = ['バナナ', 'ミカン', 'イチゴ'] df = df.reindex(pd.MultiIndex.from_product([shops, products], names=['店舗', '商品']), fill_value=0) print(df)