Python | データ処理:resample

Python
スポンサーリンク
  1. 概要(resampleは「時系列の頻度を変えて、期間ごとに集計・補間する」)
  2. 基本の使い方(インデックスを日時にしてから、ruleで頻度を指定)
    1. 日次データを月次へ集計(ダウンサンプリングの最小例)
    2. 列を基準にしたリサンプリング(onを使う)
  3. ダウンサンプリングとアップサンプリング(集計と補間の型)
    1. ダウンサンプリング(細かい→粗い)で集計する
    2. アップサンプリング(粗い→細かい)で補間する
  4. 重要パラメータの深掘り(rule・closed/label・origin・offset)
    1. rule(頻度文字列)の主な例
    2. closed と label(区間に含める端・区間ラベルの位置)
    3. origin と offset(区間の起点を揃える)
  5. 集計の表現力(aggで複数指標、OHLC、グループ併用)
    1. 複数の集計を一度に出す(agg)
    2. 金融系のOHLC(始値・高値・安値・終値)
    3. Grouperでカテゴリ別×期間集計を同時に
  6. 実践例(欠損と補間の設計、日次レポート、ピーク検出の前処理)
    1. 欠損と補間の安全な流れ(アップサンプル→補間→集計)
    2. JSTの営業日レポート(TZ整備→日次集計)
    3. ピーク検出前のスムージング(短周期→長周期の移動平均)
  7. つまずき対策(datetime必須、境界の意味、アップサンプルの欠損、順序の固定)
    1. datetimeに変換してから使う
    2. 境界(closed)とラベル(label)を意識する
    3. アップサンプルは必ず欠損が生じる
    4. 並べ替えは先に
  8. まとめ(「datetimeへ→頻度指定→集計/補間」。境界とラベルで“意図通りの期間”を作る)

概要(resampleは「時系列の頻度を変えて、期間ごとに集計・補間する」)

pandasのresampleは、時系列データを別の時間間隔(例:日→週、分→時)へ変換するためのメソッドです。ダウンサンプリング(粗くする)では期間ごとの合計・平均などを計算し、アップサンプリング(細かくする)では欠損が生じるため前後補完を組み合わせて使います。扱う列(またはインデックス)は必ずdatetime型にしてから適用します。


基本の使い方(インデックスを日時にしてから、ruleで頻度を指定)

日次データを月次へ集計(ダウンサンプリングの最小例)

import pandas as pd

daily = pd.DataFrame({
    "date": pd.to_datetime(["2025-01-01", "2025-01-02", "2025-01-15", "2025-02-01"]),
    "sales": [100, 120, 80, 200]
}).set_index("date")

monthly_sum = daily.resample("M")["sales"].sum()
print(monthly_sum)
# 2025-01-31    300
# 2025-02-28    200
Python

インデックスがdatetimeなら、”M”(月末)などの頻度文字列で集計できます。sum/mean/count/first/last/median/ohlcなどが使えます。

列を基準にしたリサンプリング(onを使う)

df = pd.DataFrame({
    "ts": ["2025-01-01 09:00", "2025-01-01 09:30", "2025-01-01 10:10"],
    "value": [10, 15, 7]
})
df["ts"] = pd.to_datetime(df["ts"])

hourly_mean = df.resample("H", on="ts")["value"].mean()
print(hourly_mean)
Python

時刻がインデックスでない場合はon=”列名”を指定します。


ダウンサンプリングとアップサンプリング(集計と補間の型)

ダウンサンプリング(細かい→粗い)で集計する

# 1分ごと → 5分ごとの平均
minute = pd.DataFrame({
    "ts": pd.date_range("2025-01-01 09:00", periods=5, freq="T"),
    "x": [10, 12, 11, 13, 9]
}).set_index("ts")

m5_mean = minute.resample("5T")["x"].mean()
print(m5_mean)
Python

より長い間隔へまとめるときは、期間ごとの集計を選びます(mean/sumなど)。

アップサンプリング(粗い→細かい)で補間する

# 日次 → 時間ごと。まずアップサンプルで穴ができる → 前方補完で埋める
daily = pd.DataFrame({
    "date": pd.to_datetime(["2025-01-01", "2025-01-03"]),
    "y": [100, 130]
}).set_index("date")

hourly = daily.resample("H")["y"].asfreq()       # 値が存在する時刻だけ保持(ほかはNaN)
hourly_filled = hourly.ffill()                   # 直前値で補間
print(hourly_filled.head(6))
Python

アップサンプリングは欠損(NaN)が生じるため、ffill(前方補完)やbfill(後方補完)、interpolate(線形など)を組み合わせます。


重要パラメータの深掘り(rule・closed/label・origin・offset)

rule(頻度文字列)の主な例

  • “D”(日)、”W”(週)、”M”(月末)、”MS”(月初)、”Q”(四半期末)、”Q-DEC”(12月決算の四半期末)
  • “H”(時)、”T”または”min”(分)、”S”(秒)
  • “5T”(5分)、”15min”(15分)などの複合指定も可能

頻度は「集計区間の切り方」を決めます。月初か月末か、週の境界をどこにするかなどを目的に合わせて選びます。

closed と label(区間に含める端・区間ラベルの位置)

# 週次集計の端点・ラベル制御
weekly = minute.resample("W", closed="right", label="right")["x"].sum()
Python
  • closed: “left”/”right”で、区間に含める端を決めます。
  • label: “left”/”right”で、出力インデックス(区間代表時刻)をどちらにするか決めます。 「どの日に属するか」「どこにラベルを置くか」がレポートの見え方に直結します。

origin と offset(区間の起点を揃える)

# 1時間区切りの起点を 09:00 にずらしたい場合
hourly = minute.resample("H", origin="start_day", offset="9min")["x"].sum()
Python

origin(起点)とoffset(ずれ)で区切りを意図通りに合わせます。業務上の「締め時刻」がある場合に有効です。


集計の表現力(aggで複数指標、OHLC、グループ併用)

複数の集計を一度に出す(agg)

monthly = daily.resample("M")["sales"].agg(["sum", "mean", "count"])
print(monthly)
Python

ひとつのresampleチェーンで複数指標を同時に計算できます。

金融系のOHLC(始値・高値・安値・終値)

price = pd.DataFrame({
    "ts": pd.date_range("2025-01-01 09:00", periods=5, freq="T"),
    "p": [100, 103, 101, 105, 104]
}).set_index("ts")

candles = price["p"].resample("5T").ohlc()
print(candles)
Python

価格系列の定番指標を期間ごとにまとめられます。

Grouperでカテゴリ別×期間集計を同時に

df = pd.DataFrame({
    "ts": pd.date_range("2025-01-01", periods=6, freq="D"),
    "store": ["A","A","B","B","A","B"],
    "sales": [10,12,8,9,11,7]
})

df["ts"] = pd.to_datetime(df["ts"])
out = df.groupby([pd.Grouper(key="ts", freq="W"), "store"])["sales"].sum().unstack("store")
print(out)
Python

グループ(店舗など)と時間の両方で集計するなら、Grouperが強力です。


実践例(欠損と補間の設計、日次レポート、ピーク検出の前処理)

欠損と補間の安全な流れ(アップサンプル→補間→集計)

raw = pd.DataFrame({
    "ts": pd.to_datetime(["2025-01-01 10:00", "2025-01-01 12:00"]),
    "value": [100, 130]
}).set_index("ts")

hourly = raw["value"].resample("H").asfreq()
hourly = hourly.interpolate(method="time").round(1)   # 時間に沿った補間
daily_sum = hourly.resample("D").sum()
print(daily_sum)
Python

アップサンプルでできた穴は、ffill/bfillかinterpolateで文脈に合う形に埋め、次の集計へ送ります。

JSTの営業日レポート(TZ整備→日次集計)

log = pd.DataFrame({
    "ts": ["2024-12-31T15:00:00Z", "2025-01-01T02:00:00Z"],
    "amount": [10, 20]
})
ts_utc = pd.to_datetime(log["ts"], utc=True)
ts_jst = ts_utc.dt.tz_convert("Asia/Tokyo")
daily = pd.DataFrame({"date": ts_jst.dt.date, "amount": log["amount"]})
report = daily.groupby("date", as_index=False)["amount"].sum()
print(report)
Python

タイムゾーンを揃えた上で日次集計すると、日付またぎの誤差がなくなります。

ピーク検出前のスムージング(短周期→長周期の移動平均)

s = pd.Series([10, 12, 11, 13, 9], index=pd.date_range("2025-01-01 09:00", periods=5, freq="T"))
m5_mean = s.resample("5T").mean()
smooth = m5_mean.rolling(window=3, min_periods=1).mean()  # さらに滑らかに
print(smooth)
Python

リサンプリングと移動平均を組み合わせると、ノイズの多い系列でも傾向が見えやすくなります。


つまずき対策(datetime必須、境界の意味、アップサンプルの欠損、順序の固定)

datetimeに変換してから使う

時刻列がobject(文字列)のままだとresampleは動きません。pd.to_datetimeで必ず日時型へ変換し、インデックスにセットするかonで指定します。

境界(closed)とラベル(label)を意識する

「どの区間に含めるか」「どこにラベルを置くか」はレポートの日付と整合性に関わります。週次・月次レポートは、仕様に合わせてclosed/labelを明示します。

アップサンプルは必ず欠損が生じる

asfreqやresampleで細かくするとNaNが生まれます。ffill/bfill/interpolateをセットで考え、補間後のdtypeや数値の意味(過剰な滑らかさの副作用)に注意します。

並べ替えは先に

時系列処理はソート済みが前提です。to_datetime→sort_valuesで順序を固定してからresampleすると、境界や補間の挙動が安定します。


まとめ(「datetimeへ→頻度指定→集計/補間」。境界とラベルで“意図通りの期間”を作る)

resampleは、時系列の頻度を変えて期間ごとの集計や補間を行うための中核メソッドです。まず日時型へ正規化し、ruleで目的の間隔へ。ダウンサンプリングはsum/meanなどで集計、アップサンプリングはffill/bfill/interpolateで穴を埋める。closed/label/origin/offsetで区間の境界とラベルを制御すれば、レポートの仕様にぴたりと合わせられます。この型を身につければ、初心者でも“滑らかで正確な”時系列整形と集計が自信を持って書けます。

タイトルとURLをコピーしました