前回(Python 100本ノック その1)の続きです。
今は『Python実践データ分析100本ノック』という本を進めています。
この本は、1~100本目まで例題をひたすらこなしていくという内容になっています。
実際に手を動かしていて難しかったところを書き残していきます。
DataFrameにindex(インデックス)があることを知る
ノック25本目の解説で分からなかったポイントが、こちらの groupby の中で使用されている『as_index=False』です。
use_log.groupby(["YYYYMM","customer_id"],as_index=False).count()
そもそもDataFrameのas_indexは何ぞや?という感じです。
データベースのindex(インデックス)は多少は理解していましたが、DataFrameのindex(インデックス)は今まで考えたことがありませんでした。
そんなPythonを初めて2週間目の私が解説したいと思います。
DataFrameのindex(インデックス)とは
まずは、以下のサンプルデータを見てください。pinkで色付けしている部分がindex(インデックス)です。
>>> df = pd.DataFrame({
... 'YYYYMM':["201804","201804","201804","201805","201805","201805","201805","201805","201805","201806"],
... 'userid':["A01","A01","B02","A01","A01","B02","B02","B02","B02","B02"],
... 'flag':["1","1","1","1","1","1","1","1","1","1"]})
>>> print(df)
YYYYMM userid flag
0 201804 A01 1
1 201804 A01 1
2 201804 B02 1
3 201805 A01 1
4 201805 A01 1
5 201805 B02 1
6 201805 B02 1
7 201805 B02 1
8 201805 B02 1
9 201806 B02 1
一番左の数字0~9とあります。これがindexだったんですね~。こんな感じでindexを表示することも出来ます。
>>> print(df.index.values)
[0 1 2 3 4 5 6 7 8 9]
また、特定の列をindexにすることも出来ます。こうすることで、思いのままにデータの検索が出来るようになります。
>>> df_i = df.set_index('YYYYMM')
>>> print(df_i)
userid flag
YYYYMM
201804 A01 1
201804 A01 1
201804 B02 1
201805 A01 1
201805 A01 1
201805 B02 1
201805 B02 1
201805 B02 1
201805 B02 1
201806 B02 1
>>>
>>> df.set_index('userid').loc["A01"]
YYYYMM flag
userid
A01 201804 1
A01 201804 1
A01 201805 1
A01 201805 1
groupby の 『as_index=False』
そして、ようやく本題のgroupbyの登場です。『as_index=True』『as_index=False』とは何なのか。それぞれの実行結果を見てみましょう。
>>> df.groupby("YYYYMM").count()
userid flag
YYYYMM
201804 3 3
201805 6 6
201806 1 1
>>>
>>> df.groupby("YYYYMM",as_index=True).count()
userid flag
YYYYMM
201804 3 3
201805 6 6
201806 1 1
>>>
>>> df.groupby("YYYYMM",as_index=False).count()
YYYYMM userid flag
0 201804 3 3
1 201805 6 6
2 201806 1 1
groupbyに『as_index=True』を追加するのと、何もしないのでは同じ結果になりましたね。"YYYYMM" が自動的にindex(インデックス)にされています。
逆に、『as_index=False』を指定した場合は "YYYYMM" はindex(インデックス)になっていません。
複数の列をgroupbyに指定した場合
続いては、複数の列をgroupbyに指定した場合はどうなるでしょうか。『as_index=True』と『as_index=False』を指定した場合、それぞれの結果を表示してみます。
>>> df.groupby(["YYYYMM","userid"],as_index=True).count()
flag
YYYYMM userid
201804 A01 2
B02 1
201805 A01 2
B02 4
201806 B02 1
>>>
>>> df.groupby(["YYYYMM","userid"],as_index=False).count()
YYYYMM userid flag
0 201804 A01 2
1 201804 B02 1
2 201805 A01 2
3 201805 B02 4
4 201806 B02 1
『as_index=True』を指定したときは、いわゆる複合index(インデックス)の状態になっていますね。"YYYYMM" と "userid" で一意になる値のセットがindex(インデックス)となっています。
ここまで来ると結果が予想できます。『as_index=False』を指定したときは、行番号がindex(インデックス)となっています。
そもそも ノック26本目の課題とは
読み込んだデータを、"YYYYMM" と "userid" で集約した DataFrame を作ることでした。それは以下で実現可能です。
>>> df["flag"] = df["flag"].astype("int")
>>> df_flag_sum = df.groupby(["YYYYMM","userid"],as_index=False).sum()
>>> df_flag_sum.rename(columns={"flag":"flag_sum"},inplace=True)
>>> df_flag_sum
YYYYMM userid flag_sum
0 201804 A01 2
1 201804 B02 1
2 201805 A01 2
3 201805 B02 4
4 201806 B02 1
※"flag" はint型に変換して sum 出来るようにしています。
※rename の引数 inplace を True にすると、元の DataFrame が変更されます。
先が長い
100本ノックといえども、まだ26本目です。まだ半分にも到達していない。。。
明日も頑張ろう。。。
Pandas