#はじめに
pandasを使って年単位や月単位でデータ数を集計する方法について調べたので、備忘録として残します。
サンプルコードも載せていますが、メール数の集計等に使えるのではないかと思います。
# 日付情報をDatetimeIndexに変換
dates = pd.to_datetime(["2019-01-25 03:30:57", "2019-01-25 03:40:57", ...])
# DatetimeIndexをpd.Seriesに変換し、to_periodで指定の周期ごとにまとめる
dates = pd.Series(index=dates)
dates = dates.to_period("Y").index
# value_countsで各周期ごとのデータ数をカウントする.
dates.value_counts().sort_index()
以下はサンプルです。以下の例では過去に受信したメール数を年、月、週ごとに集計してエクセルに出力しています。
# -*- coding: utf-8 -*-
import argparse
import datetime
import email
import email.encoders
import mailbox
import re
import os
import sys
import pandas as pd
from pandas import ExcelWriter
#MAILBOX_PATH: mailboxのパスを指定する
#以下はubuntu上のthunderbirdのmailboxのパスの例
#MAILBOX_PATH = "~/.thunderbird/XXXX/ImapMail/XXX.or.jp/INBOX"
MAILBOX_PATH = None
if not MAILBOX_PATH:
print("MAILBOX_PATH is not set")
sys.exit(1)
def save_mail_statistics(dates):
#出力先エクセル名:result.xlsx
writer = ExcelWriter("result.xlsx")
#pd.SeriesのindexにDatetimeIndexをセット
dates = pd.Series(index=dates)
#1. to_period("Y")で同一年ごとにデータをまとめる
years = dates.to_period("Y").index
#年ごとのメール数をカウント. sort_indexで日付の出力順をソート
years = years.value_counts().sort_index()
#"num_by_year"シートに出力
years.to_excel(writer, sheet_name="num_by_year")
#2. to_period("M")で同一月ごとにデータをまとめる
months = dates.to_period("M").index
#月ごとのメール数をカウント. sort_indexで日付の出力順をソート
months = months.value_counts().sort_index()
#"num_by_month"シートに出力
months.to_excel(writer, sheet_name="num_by_month")
#3. to_period("M")で同一週ごとにデータをまとめる
weeks = dates.to_period("W").index
#週ごとのメール数をカウント. sort_indexで日付の出力順をソート
weeks = weeks.value_counts().sort_index()
#"num_by_week"シートに出力
weeks.to_excel(writer, sheet_name="num_by_week")
def decode_header(data, encoding):
if encoding is not None:
ret = data.decode(encoding)
elif isinstance(data, bytes):
ret = data.decode()
else:
ret = data
return ret.strip()
def iterate_mail_headers(path):
mail_box = mailbox.mbox(path)
for mail in mail_box:
try:
data = email.header.decode_header(mail["Date"])
date = decode_header(data[0][0], data[0][1])
yield date
except (TypeError, UnicodeDecodeError, UnicodeEncodeError) as e:
print(e)
def parse_email_headers(path):
dates = []
for date in iterate_mail_headers(path):
dates.append(date)
#メールヘッダの日付をDatetimeIndexに変換
dates = pd.to_datetime(dates)
return dates
def main():
df = parse_email_headers(MAILBOX_PATH)
save_mail_statistics(df)
if __name__ == "__main__":
main()
エクセルへの出力結果を一部抜粋します。
- num_by_yearシート
- num_by_monthシート
- num_by_weekシート