質問: ### 前提・実現したいこと 前提:hoge国とfoo国全員の名前が入った名簿があり、天才の人にはフラグが立っているとします ``` df.groupby(["国名"], as_index=False)["名前", "flag"].agg({"id": ['count'],"flag": ["count"]) ``` 上記コードを実行した結果(1) | 国名 | 人口 | flag | | --- | --- | --- | | hoge | 100 | 50 | | foo | 200 | 20 | ### 実現したい形(2) | 国名 | 人口 | flag | 天才の割合 | | --- | --- | --- | --- | | hoge | 100 | 50 | 0.5 | | foo | 200 | 20 | 0.1 | 上記の様に割合を入れたいです。かつ、1の集計をデータフレームにして、それを2にするのではなく、 一つのコードで2の形にしたいです。 ### 試したこと ``` def make_rate(population, target): return target / population ``` 上記のような関数を作ってgroupby•aggを使用すれば行けるかと思ったのですが、引数が2つある時指定の仕方がわかりませんでした。 よろしくお願い致します。
回答: 質問のコード、色々と嘘がありませんか? ・`df.groupby(["国名"], as_index=False)["名前", "flag"]` とカラムを`["名前"と"flag"]`の2つにフィルタリングしているが、 `.agg()` では "id" と "flag" になっている ・更に結果の表のカラム名は '人口'と'flag' になっている ・ `"flag" : "count"` の結果はデータ数が得られるので "flag"の数にはならないはずだが、結果は "flag"の数になっている ・結果は MultuIndexになるはずだがなっていない、 何を行いたいのかは分かるのですが、できましたら正確な情報を記述していただきますようお願いします。 で、`flag`が`bool`であるという前提で記述すると、今回の件は ・人口はわざわざ `'名前': 'count'` または `'id': 'count'` でなくとも、 `'flag': 'count'` でも求まる ・flagの数は `'flag': 'count'` ではなく `'flag': 'sum'`となる ・flagの割合は `'flag': 'mean'` で求まる ので `DataFrame.agg()` ではなく `Series.agg()` を使って MultiIndexを回避しつつ dictデータでカラム名を設定すると ``` df.groupby(["国名"], as_index=False)['flag'].agg({'人口':'count', 'flag':'sum', '天才の割合':'mean'}) ``` とシンプルに記述できるかと思います。 動作サンプル ``` import pandas as pd import numpy as np N = 10000 df = pd.DataFrame({ '国名': np.random.choice(['hoge', 'foo'], N), 'id': np.arange(N), '名前': np.arange(N).astype('str'), 'flag': np.random.choice([True, False], N, p=[0.3, 0.7]) }) ret = df.groupby(["国名"], as_index=False)['flag'].agg({'人口':'count', 'flag':'sum', '天才の割合':'mean'}) print(ret) # 国名 人口 flag 天才の割合 #0 foo 4947 1459.0 0.294926 #1 hoge 5053 1479.0 0.292697 ```