Pandasで時間軸データを自在に操る!resampleとdt.roundを使いこなそう


PandasのSeriesオブジェクトに含まれる日時データに対して、指定した周波数に基づいて丸めを行うメソッドです。例えば、秒単位で記録された株価データを1分単位で丸めたり、月単位で記録された気温データを年単位で丸めたりすることができます。

構文

Series.dt.round(freq)

引数

  • freq: 丸めを行う周波数を指定します。有効な値は以下の通りです。
    • "S": 秒
    • "T": 分
    • "H": 時間
    • "D": 日
    • "W": 週
    • "M": 月
    • "Q": 四半期
    • "A": 年

import pandas as pd

# サンプルデータを作成
data = pd.Series([pd.Timestamp('2023-01-01 09:10:15'), pd.Timestamp('2023-01-01 09:12:34'), pd.Timestamp('2023-01-01 09:15:00')], name='timestamp')

# 1分単位で丸める
result = data.dt.round('T')
print(result)
0    2023-01-01 09:10:00
1    2023-01-01 09:12:00
2    2023-01-01 09:15:00
Name: timestamp, dtype: datetime64[ns]
  • 夏時間 (DST) における処理は、nonexistentambiguous オプションを使用して制御できます。
  • タイムゾーン情報が設定されている場合、丸めは現地時間に基づいて行われます。


import pandas as pd
import matplotlib.pyplot as plt

# サンプルデータを作成
data = pd.DataFrame({
    'date': pd.to_datetime(['2023-01-01 09:10:15', '2023-01-01 09:12:34', '2023-01-01 09:15:00', '2023-01-01 09:17:22']),
    'price': [100.50, 101.23, 102.45, 101.89]
})

# 1分単位で丸めた株価データ
rounded_price = data['price'].dt.round('T')

# グラフで可視化
plt.figure(figsize=(10, 6))
plt.plot(data['date'], data['price'], label='元データ')
plt.plot(data['date'], rounded_price, label='1分単位で丸めたデータ')
plt.legend()
plt.xlabel('時間')
plt.ylabel('株価')
plt.title('秒単位の株価データを1分単位で丸める')
plt.show()

例2:月単位の気温データを年単位で丸める

import pandas as pd

# サンプルデータを作成
data = pd.Series([10.2, 7.8, 5.6, 9.3, 12.5, 15.7, 18.4, 16.2, 13.9, 11.1, 8.5, 6.3], index=pd.to_datetime(['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06', '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12']))

# 年単位で丸めた気温データ
rounded_temp = data.dt.round('A')

# 結果を表示
print(rounded_temp)

出力

2020-01-01    10.0
2020-02-01    8.0
2020-03-01    6.0
2020-04-01    9.0
2020-05-01   12.0
2020-06-01   16.0
2020-07-01   18.0
2020-08-01   16.0
2020-09-01   14.0
2020-10-01   11.0
2020-11-01    8.0
2020-12-01    6.0
dtype: float64

例3:夏時間 (DST) における処理

import pandas as pd

# サンプルデータを作成
data = pd.Series([pd.Timestamp('2023-03-12 01:00:00'), pd.Timestamp('2023-03-12 02:00:00'), pd.Timestamp('2023-03-12 03:00:00')], name='timestamp')

# 1時間単位で丸める
result = data.dt.round('H', nonexistent='shift_forward', ambiguous='raise')
print(result)
0    2023-03-12 01:00:00
1    2023-03-12 03:00:00
Name: timestamp, dtype: datetime64[ns]
  • Pandasの公式ドキュメントには
  • 上記の例はあくまで一例です。具体的な用途に合わせて、引数やオプションを変更してください。


以下に、いくつかの代替方法とその利点と欠点をご紹介します。

floor() と ceil() メソッド

  • 欠点:
    • 指定した周波数よりも粗い丸めしかできない
    • 例えば、10分単位で丸めたいのに、floor() メソッドだと5分単位でしか丸められない
  • 利点:
    • シンプルで分かりやすい構文
    • 高速に処理できる
# 10分単位で丸める
data['rounded_time'] = data['timestamp'].dt.floor('10T')

resample() メソッド

  • 欠点:
    • dt.round メソッドよりも処理速度が遅い
  • 利点:
    • アップサンプリングやダウンサンプリングなど、柔軟な操作が可能
    • 欠損値処理を指定できる
# 10分単位で丸める
data = data.resample('10T').mean()

カスタム関数

  • 欠点:
    • 複雑な処理になる可能性がある
    • 処理速度が遅くなる可能性がある
  • 利点:
    • 独自の丸め処理を実装できる
def round_to_nearest_ten_minutes(timestamp):
    # 10分単位の最も近い時刻を計算
    rounded_time = timestamp.round('T')
    minutes = rounded_time.minute
    if minutes % 10 == 0:
        pass
    elif minutes < 5:
        rounded_time -= timedelta(minutes=minutes)
    else:
        rounded_time += timedelta(minutes=10 - minutes)
    return rounded_time

# 10分単位で丸める
data['rounded_time'] = data['timestamp'].apply(round_to_nearest_ten_minutes)

外部ライブラリの利用

  • 欠点:
    • 別途ライブラリをインストールする必要がある
  • 利点:
    • pandas にはない機能を利用できる

例えば、dateutil ライブラリを使用して、10分単位で丸めることができます。

import dateutil.parser

def round_to_nearest_ten_minutes(timestamp_str):
    # 文字列から `datetime` オブジェクトに変換
    timestamp = dateutil.parser.parse(timestamp_str)

    # 10分単位の最も近い時刻を計算
    rounded_time = timestamp.round(minute=10)
    return rounded_time.strftime('%Y-%m-%d %H:%M:%S')

# 10分単位で丸める
data['rounded_time'] = data['timestamp'].apply(round_to_nearest_ten_minutes)

最適な代替方法の選択

どの代替方法が最適かは、状況によって異なります。

  • pandas にはない機能が必要な場合は、外部ライブラリを利用します。
  • 独自の丸め処理が必要な場合は、カスタム関数を使用します。
  • より柔軟な操作が必要な場合は、resample() メソッドがおすすめです。
  • シンプルで高速な処理が必要な場合は、floor()ceil() メソッドがおすすめです。