exportしたcsvをpandasで集計

#目的
ブクログには読書記録という機能から

* 月ごとにどんな本をどれ位読んだか（観たか）
* 月、年ごとにどの本を読んだか（観たか）

という時系列でどんな本読んだ～？みたいな情報を手軽に確認できる機能がある。

が、いつの間にか機能が簡略化されてしまったようで
2年前以上の詳細が参照できない。
月合計で何冊読んだ？くらいはわかるが、どの本読んだかがぱっとわからない。

無くても困らないっちゃ困らないのだが、
たまに昔の読書を振り返る時とかに不便、というか無いと寂しい。

ただ、ブクログは登録した本の一覧をcsvでexportできる。
ということはそのcsvで集計すればいっか。

csvをExcel読み込み→集計でもよいのだが
読書メモに集計には不要な情報を大量に突っ込んでおり
なんとなくデータの整形が面倒そうなので、pandasで集計してみる。

##集計用スクリプト

```Python:agg_csv.py
import pandas as pd

def agg_execute(filename):

    csv_header = [
        "サービスID",
        "アイテムID",
        "13桁ISBN",
        "カテゴリ",
        "評価",
        "読書状況",
        "レビュー",
        "タグ",
        "読書メモ(非公開)",
        "登録日時",
        "読了日",
        "タイトル",
        "作者名",
        "出版社名",
        "発行年",
        "ジャンル",
        "ページ数",
    ]
    book_log_df = pd.read_csv(
        filename,
        names=csv_header,
        encoding="shift_jis",
    )

    """
    データクリーニング
    欲しいデータは読み終わった＆読了日を設定しているデータ
    """
    filter_df = book_log_df[
        (book_log_df["読書状況"] == "読み終わった")
        & (book_log_df["読了日"] != None)
        & (book_log_df["読了日"] != "0000-00-00 00:00:00")
    ].copy()

    # 読了日を時系列データとして設定
    filter_df["読了日"] = pd.to_datetime(filter_df["読了日"])
    filter_df = filter_df.set_index("読了日")

    # 時系列のインデックスを設定
    df_m = filter_df.set_index(
        [filter_df.index.year, filter_df.index.month, filter_df.index]
    )
    df_m.index.names = ["year", "month", "読了日"]

    # 月ごとのジャンル内訳
    df_m_by_genre = (
        df_m[["ジャンル"]].groupby(["year", "month", "ジャンル"]).size().sort_index()
    )
    df_m_by_genre.name = "冊"
    df_m_by_genre.to_csv("result_count_by_genre_yyyymm.csv", encoding="utf-8")

    # 月ごとのページ数合計
    df_m_by_page = df_m["ページ数"].sum(level=("year", "month")).sort_index()
    df_m_by_page.to_csv("result_page_sum.csv", encoding="utf-8")

    # 月ごとのタイトル一覧
    df_m_by_title = df_m["タイトル"].sum(level=("year", "month"))
    df_m_by_title = df_m["タイトル"].groupby(level=("year", "month")).apply(list)
    df_m_by_title.to_csv("result_title_sum.csv", encoding="utf-8")


if __name__ == "__main__":
    # 読み込むcsvを指定
    agg_execute("booklog.csv")

```

##実行結果
```result_count_by_genre_yyyymm.csv
year,month,ジャンル,冊
2020,1,映画,3
2020,1,本,12
2020,2,映画,1
2020,2,本,16
2020,3,本,4
2020,4,映画,3
2020,5,映画,2
2020,5,本,15
2020,6,マンガ,1
2020,6,映画,2
2020,6,本,31
```

これが見たかっただけです、はい。

result_page_sum.csvでページ/month,
result_title_sum.csvで月ごとの読んだ本のタイトルをずらずら出力。

##メモ

```Python:before.py
filter_df = book_log_df[
    (book_log_df["読書状況"] == "読み終わった")
    & (book_log_df["読了日"] != None)
    & (book_log_df["読了日"] != "0000-00-00 00:00:00")
]
```

最初こんな感じで書いてたら、
それっぽい結果は出るんだけれど
SettingWithCopyWarningという警告が出る。

```Python:after.py
filter_df = book_log_df[
    (book_log_df["読書状況"] == "読み終わった")
    & (book_log_df["読了日"] != None)
    & (book_log_df["読了日"] != "0000-00-00 00:00:00")
].copy()
```

今回のケースではそのままでも結果に差異がなかったのだが、、
普通に=で代入しちゃうと元データに対する処理か、
新しく作成しようとしたデータに対しての処理なのかが
pandas側では判断できないので、ちゃんとcopyして渡すこと。

タイトルじゃなくてISBNのリスト残す方が、
今後別サービスとかに移行する時楽そうなので、
そっちも保存するようにしたほうがいいかも。

##thx

[pandas.DataFrame, Seriesを時系列データとして処理]
(https://note.nkmk.me/python-pandas-time-series-datetimeindex/)
[pandasで時系列データの曜日や月、四半期、年ごとの合計や平均を算出]
(https://note.nkmk.me/python-pandas-time-series-multiindex/)
[Pandasのgroupbyを使った要素をグループ化して処理をする方法]
(https://deepage.net/features/pandas-groupby.html)
[pandas の SettingWithCopyWarning で苦労した話]
(https://qiita.com/HEM_SP/items/56cd62a1c000d342bd70)
[pandasのgroupbyでグループ化した文字列を結合する]
(https://qiita.com/ground0state/items/2fb8d1938220df8a0194)