Pythonのpandasで集計をした備忘です。
groupbyで集計するのにある列は合計、ある列は平均というように、集計列によって異なる集計方法で集計した備忘です。
pandasで複数の列でグルーピングして列によって違う集計
google先生で検索してもなかなかでてこなかったので備忘で残すことにしました。
やりたいことは
- 複数の列でグルーピングする。(得意先別、商品群別みたいに集計)
- 集計する値は列によって違う(単価列は平均、売上高は合計など)
検索しても、「複数列でグルーピングして集計はすべて同じ合計など」や「グルーピングは一列だけで集計は列によって変える」というのはすぐに見つかったのですが、両方を組み合わせたものは見つからなかったのでまとめたものをやってみました。
元のデータはこんな感じです。
import pandas as pd
#ヘッダーありのCSVを取り込む(header=0でヘッダー有りを指定)
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
print(df)
'''
伝票番号 日付 得意先 品名 数量 単価 売上
0 100001 2023/1/1 東京商事 Tシャツ 100 1500 150000
1 100002 2023/1/1 東京商事 ポロシャツ 50 2100 105000
2 100003 2023/1/1 神奈川商会 Tシャツ 60 1400 84000
.. ... ... ... ... ... ... ...
16 100017 2023/1/7 神奈川商会 Tシャツ 80 1600 128000
17 100018 2023/1/7 神奈川商会 ポロシャツ 20 2000 40000
18 100019 2023/1/8 群馬商店 Tシャツ 10 1500 15000
[19 rows x 7 columns]
'''
「.groupby」を使って集計する
得意先で集計する
まずは、ひとつの項目を集計をしてみます。
得意先別に数量と売上の平均を集計します。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ndf = df.groupby(['得意先'])[["数量", "売上"]].mean()
print(ndf)
'''
数量 売上
得意先
千葉商店 97.500000 251625.000000
東京商事 75.000000 127500.000000
神奈川商会 75.714286 160414.285714
群馬商店 56.666667 96250.000000
'''
複数の列で集計する
得意先別、商品別を集計対象にして、数量と売上の平均を集計してみます。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ndf = df.groupby(['得意先','品名'])[["数量", "売上"]].mean()
print(ndf)
'''
数量 売上
得意先 品名
千葉商店 Tシャツ 70.000000 108500.0
トレーナー 120.000000 365000.0
ポロシャツ 80.000000 168000.0
東京商事 Tシャツ 100.000000 150000.0
ポロシャツ 50.000000 105000.0
神奈川商会 Tシャツ 63.333333 104000.0
トレーナー 60.000000 180450.0
ポロシャツ 110.000000 225000.0
群馬商店 Tシャツ 52.500000 76625.0
ポロシャツ 65.000000 135500.0
'''
集計を単価は平均、数量・売上は合計で集計する。
先ほどと同様集計は「得意先別・商品別」で、集計方法を複数にしてみます。
単価は平均、数量と売上は合計を集計します。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ndf = df.groupby(['得意先','品名']).agg({"単価":"mean","数量": "sum", "売上": "sum"})
print(ndf)
'''
単価 数量 売上
得意先 品名
千葉商店 Tシャツ 1550.000000 70 108500
トレーナー 3025.000000 240 730000
ポロシャツ 2100.000000 80 168000
東京商事 Tシャツ 1500.000000 100 150000
ポロシャツ 2100.000000 50 105000
神奈川商会 Tシャツ 1666.666667 190 312000
トレーナー 3015.000000 120 360900
ポロシャツ 2025.000000 220 450000
群馬商店 Tシャツ 1462.500000 210 306500
ポロシャツ 2125.000000 130 271000
'''
売上は合計と件数を集計したい
groupbyだけじゃうまくいかない
「groupby」で売上を「”売上”: “sum”, “売上”:”count」で集計しようとすると、上手くいきませんでした。
後に記載したデータ個数だけが集計されます。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ndf = df.groupby(['得意先','品名']).agg({"単価":"mean","数量": "sum", "売上": "sum", "売上":"count"})
print(ndf)
'''
単価 数量 売上
得意先 品名
千葉商店 Tシャツ 1550.000000 70 1
トレーナー 3025.000000 240 2
ポロシャツ 2100.000000 80 1
東京商事 Tシャツ 1500.000000 100 1
ポロシャツ 2100.000000 50 1
神奈川商会 Tシャツ 1666.666667 190 3
トレーナー 3015.000000 120 2
ポロシャツ 2025.000000 220 2
群馬商店 Tシャツ 1462.500000 210 4
ポロシャツ 2125.000000 130 2
'''
同じ列を複数回集計したいときは列の追加で対応
売上は合計とデータ個数を集計したいときは、groupbyで合計で集計した後で、列を追加して売上のデータ個数を追加します。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ndf = df.groupby(['得意先','品名']).agg({"単価":"mean","数量": "sum", "売上": "sum"})
ndf['売上個数'] = df[['売上']].groupby([df['得意先'],df['品名']]).count()
print(ndf)
'''
単価 数量 売上 売上個数
得意先 品名
千葉商店 Tシャツ 1550.000000 70 108500 1
トレーナー 3025.000000 240 730000 2
ポロシャツ 2100.000000 80 168000 1
東京商事 Tシャツ 1500.000000 100 150000 1
ポロシャツ 2100.000000 50 105000 1
神奈川商会 Tシャツ 1666.666667 190 312000 3
トレーナー 3015.000000 120 360900 2
ポロシャツ 2025.000000 220 450000 2
群馬商店 Tシャツ 1462.500000 210 306500 4
ポロシャツ 2125.000000 130 271000 2
'''
「.pivot_table」を使って集計できる
pandasでは、「.pivot_table」を使っても集計ができます。
index、values、aggfuncには、リスト形式でそれぞれ複数の項目を設定できます。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ptdf = df.pivot_table(index=['得意先','品名'], values=["数量","売上"], aggfunc=["sum","mean"],fill_value=0)
print(ptdf)
'''
sum mean
売上 数量 売上 数量
得意先 品名
千葉商店 Tシャツ 108500 70 108500 70.000000
トレーナー 730000 240 365000 120.000000
ポロシャツ 168000 80 168000 80.000000
東京商事 Tシャツ 150000 100 150000 100.000000
ポロシャツ 105000 50 105000 50.000000
神奈川商会 Tシャツ 312000 190 104000 63.333333
トレーナー 360900 120 180450 60.000000
ポロシャツ 450000 220 225000 110.000000
群馬商店 Tシャツ 306500 210 76625 52.500000
ポロシャツ 271000 130 135500 65.000000
'''
pandasの集計のあれこれ
集計の方法で主なものは以下の通りです。
'''
mean 平均
median 中央値
mode 最頻値
sum 合計
max 最大値
min 最小値
count データ数
std 標準偏差
var 分散
'''
CSVに書き出すときは、「.to_csv」で出力できます。
エクセルで使いたいときは、「encoding=”utf-8_sig”」というように「_sig」を追加しておくと文字化けしないです。
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8", header=0)
ptdf = df.pivot_table(index=['得意先','品名'], values=["数量","売上"], aggfunc=["sum","mean"],fill_value=0)
print(ptdf)ptdf.to_csv("pd_output.csv", encoding="utf-8_sig")
元データ全件
大したデータではないですが、全行を貼り付けておきます。これをExcelに貼り付けてCSVにすれば、上記を再現できるはずです。
伝票番号 | 日付 | 得意先 | 品名 | 数量 | 単価 | 売上 |
100001 | 2023/1/1 | 東京商事 | Tシャツ | 100 | 1500 | 150000 |
100002 | 2023/1/1 | 東京商事 | ポロシャツ | 50 | 2100 | 105000 |
100003 | 2023/1/1 | 神奈川商会 | Tシャツ | 60 | 1400 | 84000 |
100004 | 2023/1/2 | 千葉商店 | トレーナー | 40 | 3000 | 120000 |
100005 | 2023/1/3 | 千葉商店 | ポロシャツ | 80 | 2100 | 168000 |
100006 | 2023/1/3 | 神奈川商会 | ポロシャツ | 200 | 2050 | 410000 |
100007 | 2023/1/3 | 群馬商店 | Tシャツ | 50 | 1450 | 72500 |
100008 | 2023/1/3 | 千葉商店 | トレーナー | 200 | 3050 | 610000 |
100009 | 2023/1/3 | 群馬商店 | ポロシャツ | 100 | 2050 | 205000 |
100010 | 2023/1/3 | 神奈川商会 | Tシャツ | 50 | 2000 | 100000 |
100011 | 2023/1/4 | 群馬商店 | Tシャツ | 60 | 1400 | 84000 |
100012 | 2023/1/5 | 神奈川商会 | トレーナー | 30 | 3030 | 90900 |
100013 | 2023/1/5 | 千葉商店 | Tシャツ | 70 | 1550 | 108500 |
100014 | 2023/1/5 | 神奈川商会 | トレーナー | 90 | 3000 | 270000 |
100015 | 2023/1/5 | 群馬商店 | ポロシャツ | 30 | 2200 | 66000 |
100016 | 2023/1/6 | 群馬商店 | Tシャツ | 90 | 1500 | 135000 |
100017 | 2023/1/7 | 神奈川商会 | Tシャツ | 80 | 1600 | 128000 |
100018 | 2023/1/7 | 神奈川商会 | ポロシャツ | 20 | 2000 | 40000 |
100019 | 2023/1/8 | 群馬商店 | Tシャツ | 10 | 1500 | 15000 |
コメント