グループ化集計して、上位N件の取得
やりたいこと
データフレームをグループ化して集計(平均)し、その上で、各グループについて上位N件を取得したい。
つまり、やることを分解すると、
- 1 グループ化して数値集計(今回は平均)
- 2 集計した数値で、各グループごとに上位N件取得
1 グループ化して集計
pandasの場合、groupby
メソッドが用意されており、これで解決できる。
dfをデータフレームとした時、
df.groupby([列番号]).集計関数
と記述する。
戻り値は、集計済みのデータフレームである。
2 集計した上で、各グループごとに上位N件
これが頭を悩ませた。
と、いうのも、データフレームのままでやろうとすると、上位N件だけ残す。ということができないからだ。
各グループで、違う項目が上位N件に来るので、表という形式をもっている限り、どうしてもソートはできない。 (各グループごとに、数値の順位を記載した行を用意する。という解決索はあるが、スマートでない気がした。)
そこで、一度、データフレームをバラして、dictにしてから、グループごとにソートする。ということを行なった。
で、面倒なのだが、ソートしてから、またデータフレームにして、出力をした。 (こんな面倒なことやらんでも、jsonで渡せたら最良だったのだが、OUTPUTにexcelで使えるデータを求められていたので、どうしてもcsvで保存する必要があった)
まずmelt
元のデータは行がキー(グループID)、列が値のインデックス。という巨大なデータフレームなので、まずは、これを変形する。
pandas.melt(df, id_vars=['列名'])
でmeltができる
dictにする
さて、これがちょっと面倒くさい。
と、いうのも、一発で簡単にdictに変換できなかったからだ。
そこで、forループを回して、行ごとに処理をすることにした。
my_dict = {}
for x in range(len(df)):
row_info = df.iloc[x]
line_info = row_info.tolist()
c_key = line_info[0] # キーになる要素
currentvalue1 = line_info[1] # 値の要素1
currentvalue2 = line_info[2] # 値の要素2
if c_key in my_dict: my_dict[c_key].append( [currentvalue1, currentvalue2] )
else: my_dict[c_key] = [[currentvalue1, currentvalue2]]
ソートして上位N件取得
上の処理でつくったdictの各キーで、ソートをし、上位N件だけ残したdict(キー:インデックス名、値:数値)を値にして、新しくdictを作ることにした。(キーは同じ)
わざわざ2重のdict構造にするのは、この後の処理でpandasのメソッドを使って、一発で目的の表に変換できるからだ。
top_n_map = {}
for key in df_map:
values_list = df_map[key]
values_list.sort(key=lambda x:(x[1]), reverse = True)
value_map = {}
for item in values_list[0:9]:
value_map[item[0]] = item[1] # インデックス名をキー、数値を値にして、2次元目のdictを保存
top_n_map[key] = value_map
データフレームにもどして、csvに保存
{キー1:{キー2:値} }
という形のdictなら、一発で下の表に変換してくれる。
_____| キー2 | キー2 | .....
キー1 | 値 | 値 | .....
キー1 | 値 | 値 | .....
キー1 | 値 | 値 | .....
これをする命令は
pandas.DataFrame.from_dict(dict)
まとめ
グループ化集計して、上位N件だけ残す処理をした。
が、ふと思ったのは、別にmeltはしなくてもよかったような気がする。
別にmeltしなくともdict {キー:list [ list [インデックス名, 数値] ] }
の形は構築できる。
無駄足を踏んだ気がするが、meltをどこかで使う機会があるかもしれないので、記録に残しておく。