2
4

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 5 years have passed since last update.

pandas 指定周期ごとのデータ数を集計する

Last updated at Posted at 2019-01-25

#はじめに
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シート

image.png

  • num_by_monthシート

image.png

  • num_by_weekシート

image.png

2
4
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
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?