0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

exportしたcsvをpandasで集計

Posted at

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

  • 月ごとにどんな本をどれ位読んだか(観たか)
  • 月、年ごとにどの本を読んだか(観たか)

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

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

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

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

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

##集計用スクリプト

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で月ごとの読んだ本のタイトルをずらずら出力。

##メモ

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

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

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)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?