Python | データ処理:時系列処理の基礎

Python
スポンサーリンク
  1. 概要(時系列の“型”を整えて、時間軸で正しく集計・解析する)
  2. datetime化と順序固定(to_datetime→並べ替え→インデックス設定)
    1. 文字列を日時へ変換して安全運転に
    2. インデックスに載せると時系列APIが使いやすい
  3. 期間集計(resample)と移動統計(rolling)
    1. 日次→月次へまとめる(ダウンサンプリング)
    2. 過去7日移動平均で平滑化(期間幅のrolling)
    3. 固定幅N点の移動統計(ノイズ除去や変動把握)
  4. 差分・シフト・期間抽出(時間軸で“変化”と“範囲”を扱う)
    1. 前日比・前週比などの差分
    2. 時系列シフト(ラグ特徴量)
    3. 期間指定で一発抽出(文字列スライスが使える)
  5. タイムゾーンと等間隔化(UTC統一→ローカル、asfreqで穴を見える化)
    1. タイムゾーンの基本設計
    2. 等間隔へ再インデックス(補間前の下ごしらえ)
  6. 例題(実務で通る“型”をひとまとめ)
    1. 売上ログをJSTへ揃え、日次レポートを作る
    2. 不規則な観測を7日移動平均で平滑化
    3. 月次集計と異常候補の検出(短期平均からの乖離)
  7. よくあるつまずきと対策(型・順序・欠損・境界の意味)
    1. datetime型にしてから操作する
    2. 並べ替えは先に
    3. 欠損(NaT/NaN)は“意味のある穴”
    4. 期間の境界とラベル位置
  8. まとめ(「datetimeへ→順序固定→期間集計・移動統計・差分」。TZと補間は設計で決める)

概要(時系列の“型”を整えて、時間軸で正しく集計・解析する)

時系列処理の基礎は、日付や時刻をdatetime型へ変換し、時間順に並べてから「期間集計」「移動統計」「シフトや差分」などの操作を行うことです。pandasはDateTimeIndex(またはon=列指定)で時系列を強力に扱えます。最初の一歩で型と順序を整えるだけで、後の集計・可視化・異常検知が安全に回ります。


datetime化と順序固定(to_datetime→並べ替え→インデックス設定)

文字列を日時へ変換して安全運転に

import pandas as pd

df = pd.DataFrame({
    "date": ["2025-01-02", "2024-12-31", "2025/01/01", "bad"],
    "sales": [100, 120, 200, 150]
})

df["date"] = pd.to_datetime(df["date"], errors="coerce")  # 変換不可はNaT
df = df.dropna(subset=["date"]).sort_values("date")
print(df.dtypes)
# date    datetime64[ns]
Python

日時型へ変換してから並べ替えるのが鉄則です。errors=”coerce”で壊れた値をNaTにでき、後で対処しやすくなります。

インデックスに載せると時系列APIが使いやすい

df = df.set_index("date")
# df.resample(...), df.rolling(...), df.loc["2025-01"] などが直感的に書ける
Python

インデックスを日時にすることで、期間指定やリサンプリングが一気にシンプルになります。


期間集計(resample)と移動統計(rolling)

日次→月次へまとめる(ダウンサンプリング)

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

頻度文字列(”D”,”W”,”M”,”MS”,”H”,”T”など)を指定し、期間ごとの合計・平均・件数を計算できます。

過去7日移動平均で平滑化(期間幅のrolling)

ma7d = df["sales"].rolling("7D").mean()       # 直近7日間の平均
ma7d_center = df["sales"].rolling("7D", center=True).mean()  # 表示上のズレを減らす
Python

期間幅の窓は不等間隔にも自然に対応します。center=Trueは折れ線の視覚的整合に便利です。

固定幅N点の移動統計(ノイズ除去や変動把握)

roll = df["sales"].rolling(window=3, min_periods=2)
smooth = roll.mean()     # 移動平均
vol    = roll.std()      # 移動標準偏差(揺らぎ)
Python

min_periodsで初期のNaNを抑え、レポートや異常検知の指標へ繋げます。


差分・シフト・期間抽出(時間軸で“変化”と“範囲”を扱う)

前日比・前週比などの差分

df["diff_1d"] = df["sales"].diff(1)    # 1ステップ差分(例:前日比)
df["pct_change"] = df["sales"].pct_change()  # 前ステップ比率
Python

diffやpct_changeで変化量・変化率を簡単に計算できます。

時系列シフト(ラグ特徴量)

df["lag_1"] = df["sales"].shift(1)  # 1ステップ前の値
df["lag_7"] = df["sales"].shift(7)  # 7ステップ前(例:週次ラグ)
Python

予測や異常検知で「過去の値」を特徴量として持たせられます。

期間指定で一発抽出(文字列スライスが使える)

jan = df.loc["2025-01"]            # 2025年1月の範囲
range_df = df.loc["2024-12-31":"2025-01-02"]  # 端点を含む範囲抽出
Python

DateTimeIndexなら直感的な文字列で範囲を切れます。


タイムゾーンと等間隔化(UTC統一→ローカル、asfreqで穴を見える化)

タイムゾーンの基本設計

ts_utc = pd.to_datetime(["2024-12-31T15:00:00Z","2025-01-01T03:00:00Z"], utc=True)
ts_jst = ts_utc.tz_convert("Asia/Tokyo")
Python

混在TZはまずUTCへ正規化し、表示や集計で必要なローカルTZへ変換すると安全です。

等間隔へ再インデックス(補間前の下ごしらえ)

s = pd.Series([100, 120], index=pd.to_datetime(["2025-01-01 10:00","2025-01-01 12:00"]))
eq = s.asfreq("H")       # 1時間間隔に再インデックス(欠損はNaN)
filled = eq.ffill()      # 前方補完で穴埋め
Python

asfreqで“穴”を可視化し、ffill/bfill/interpolateで文脈に合う補間を選びます。


例題(実務で通る“型”をひとまとめ)

売上ログをJSTへ揃え、日次レポートを作る

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

時差を正しく処理してからグルーピングすると、日付またぎのズレがなく信頼できるレポートになります。

不規則な観測を7日移動平均で平滑化

df = pd.DataFrame({
    "date": pd.to_datetime(["2025-01-01","2025-01-02","2025-01-05","2025-01-10","2025-01-11"]),
    "value": [100, 120, 80, 200, 150]
}).set_index("date")

smooth = df["value"].rolling("7D").mean()
print(smooth)
Python

期間窓のrollingは不等間隔データでも自然に使えます。グラフ化するとトレンドが一目で掴めます。

月次集計と異常候補の検出(短期平均からの乖離)

monthly = df.resample("M")["value"].sum()
ma3 = df["value"].rolling(3, min_periods=2).mean()
sd3 = df["value"].rolling(3, min_periods=2).std()
z = (df["value"] - ma3) / sd3
anomaly = df[z.abs() >= 2]
Python

期間集計で俯瞰しつつ、短期の標準化乖離で“飛び値”を候補として抽出します。


よくあるつまずきと対策(型・順序・欠損・境界の意味)

datetime型にしてから操作する

文字列のままでは時系列APIが動きません。to_datetimeで型を揃え、NaTはdropnaやfillnaの方針を決めてから前へ進みます。

並べ替えは先に

sort_values(“date”)(またはインデックス順)で昇順を固定してからresampleやrollingを使うと、窓や区間の挙動が安定します。

欠損(NaT/NaN)は“意味のある穴”

アップサンプルや壊れた日付で欠損は必ず出ます。補間の前提(保持・前方補完・後方補完・線形)を最初に決め、dtypeの変化に注意します。

期間の境界とラベル位置

週次や月次レポートではclosed/labelの指定で「どの日に属するか」「どこにラベルを置くか」を明示します。仕様に合わせて統一すると誤解が減ります。


まとめ(「datetimeへ→順序固定→期間集計・移動統計・差分」。TZと補間は設計で決める)

時系列処理の土台は、日時型への変換と昇順固定です。その上でresampleで期間集計、rollingで移動統計、diff/pct_change/shiftで変化とラグを扱う。タイムゾーンはUTC統一→必要に応じてローカルへ、アップサンプリングの欠損は補間戦略を先に決める。この型を身につければ、初心者でも“正確で説得力のある”時系列前処理とレポートを安定して作れます。

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