0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで学ぶ時系列予測 ― e-learningで基礎から実践まで Part 1

0
Posted at

Pythonで学ぶ時系列予測 ― e-learningで基礎から実践まで Part 1

はじめに

雨量、水位、気温、交通量、電力需要、売上など、時間とともに変化するデータは身の回りに数多くあります。

例えば、10分ごとの雨量であれば次のように記録されます。

10:00  0.0 mm
10:10  0.5 mm
10:20  2.0 mm
10:30  5.5 mm
10:40  8.0 mm

この並びを見れば、単に「5つの数値がある」のではなく、時間とともに雨が強くなっていることが分かります。

そして実際に知りたいのは、多くの場合その先です。

このあと雨はさらに強くなるのか
1時間後の河川水位はどうなるのか
明日の電力需要はどのくらいになるのか

このように、時間順に並んだデータから先の状態を考えるのが**時系列予測(Time Series Forecasting)**です。

この連載では、Jason Brownlee著 Introduction to Time Series Forecasting with Python を参考にしながら、Pythonを使って時系列予測を基礎から順番に学びます。

ただし、本の内容をそのまま追うだけではありません。

実際に手を動かしながら理解できるように、e-learning形式で進めます。

読む
 ↓
考える
 ↓
Pythonで試す
 ↓
結果を確認する
 ↓
少し条件を変えてみる

最初から高度なモデルを使うのではなく、小さなデータで仕組みを確認してから、少しずつ実際の時系列データへ広げていきます。


1. このe-learningで目指すところ

このシリーズの目的は、ARIMAや機械学習のコードを動かせるようになることだけではありません。

時系列予測では、モデルを作る前に理解しておかなければならないことがかなりあります。

例えば、次のような点です。

時系列予測の基本

  • 時間順序をどう扱うか
  • 過去のどこまでを入力として使うか
  • 欠測値や異常値をどう扱うか
  • トレンドや季節性をどう見るか
  • 学習データとテストデータをどう分けるか
  • 単純な予測より本当に良くなっているか
  • 予測誤差をどう評価するか

モデルが動いて予測値が出ても、評価方法が間違っていれば、その結果を信用することはできません。

そこでこのe-learningでは、最終的に次の流れを自分で組み立てられることを目標にします。

01_forecasting_workflow.png


2. 全体はPart 1からPart 7まで

このe-learningは、Part 1からPart 7まで順番に進めます。

02_learning_map.png

それぞれで何を学ぶのか、最初に全体像を見ておきます。


Part 1 ― Fundamentals

最初は時系列予測の基礎です。

ここでは、まだ高度な予測モデルは使いません。

まず、

時系列とは何か
      ↓
予測とは何か
      ↓
過去と未来をどう表すか
      ↓
機械学習で扱える形へ変換する

ところまで進みます。

特に重要なのが、次の考え方です。

t-3
 t-2
  t-1
   ↓
   t

過去の観測値を使って、現在または未来を予測する形に変換します。

この考え方は、後でARIMA、Random Forest、XGBoost、LSTMなどへ進んでも基本は変わりません。

Part 1のゴール

Part 1を終えた時点で、次のことができれば十分です。

  • 時系列データとは何か説明できる
  • t-1 や t+1 の意味が分かる
  • Forecast Horizonを説明できる
  • Sliding Windowの仕組みが分かる
  • 時系列を教師あり学習形式へ変換できる

Part 2 ― Data Preparation

次はデータを整えます。

実際の観測データは、最初からきれいに並んでいるとは限りません。

10:00  1.20
10:10  1.25
10:20  欠測
10:30  1.42

のような欠測があったり、観測間隔が一定でなかったりします。

Part 2では、

CSV
 ↓
pandas
 ↓
日時を整理
 ↓
Lagを作る
 ↓
Rolling Windowを作る
 ↓
Resampling
 ↓
必要な変換

という流れを学びます。

主な内容は次のとおりです。

  • pandasによる時系列データの読み込み
  • DatetimeIndex
  • Lag特徴量
  • Rolling Window
  • Resampling
  • 移動平均
  • 対数変換
  • Box-Cox変換

Part 3 ― Temporal Structure

Part 3では、時系列そのものの性質を調べます。

例えば、長期的に増えているならTrendがあります。

毎年同じ季節に増えるならSeasonalityがあります。

さらに、現在の値と少し前の値に強い関係があれば自己相関があります。

主に扱うのは次の内容です。

  • White Noise
  • Random Walk
  • Trend
  • Seasonality
  • 差分
  • 定常性
  • ADF検定
  • 自己相関

ここでは、グラフを見るだけではなく、

この時系列にはどのような時間的な特徴があるのか

を説明できるようになることを目指します。


Part 4 ― Model Evaluation

予測モデルを作る前に、評価方法を決めます。

時系列では、普通の機械学習のようにデータを無条件にランダムシャッフルすると問題が起こります。

基本は、

過去 ----------------------------→ 未来

Train                              Test

という順序を守ります。

Part 4では、次の内容を扱います。

  • Train/Test分割
  • Walk Forward Validation
  • Forecast Error
  • Bias
  • MAE
  • MSE
  • RMSE
  • Persistence Model
  • 残差解析

ここでの目標は、単に「予測値が出た」で終わらず、

このモデルは本当に良い予測をしているのか

を判断できるようになることです。


Part 5 ― Forecast Models

ここで予測モデルへ進みます。

中心になるのは、

  • AR
  • MA
  • ARMA
  • ARIMA

です。

ARIMAでは、

ARIMA(p, d, q)

という3つのパラメータを扱います。

さらに、ACF、PACF、Grid Search、予測区間なども確認します。

モデルを実行するだけでなく、なぜその設定にしたのかを説明できるところまで進めます。


Part 6 ― Forecasting Projects

ここまで学んだ内容を使って、予測問題を最初から最後まで解きます。

流れは次のようになります。

問題を決める
 ↓
データを見る
 ↓
Train/Testを決める
 ↓
基準モデルを作る
 ↓
時系列の特徴を調べる
 ↓
モデルを作る
 ↓
評価する
 ↓
改善する
 ↓
最終モデルを決める

ここまで来ると、Part 1から学んできた内容が一つにつながります。


Part 7 ― Conclusions

最後に全体を振り返ります。

ここまでで学んだ古典的な時系列予測を土台にすると、その先にある、

  • Random Forest
  • XGBoost
  • LightGBM
  • LSTM
  • GRU
  • Transformer
  • 状態空間モデル
  • ベイズ時系列モデル

などへ進みやすくなります。

最初から高度なモデルへ進むのではなく、まず時系列予測の基本を一通り身につけることが、このシリーズの狙いです。


3. e-learningの進め方

各Partは、できるだけ同じ形で進めます。

03_elearning_cycle.png

いきなり大量のデータを扱うことはしません。

最初は5個、10個程度の値を使って、何をしているのかを目で追えるようにします。

そのあとで実際のCSVや観測データへ広げます。


4. 学習環境

このe-learningでは、Docker + JupyterLab を基本の学習環境にします。

時系列の勉強では、コードをまとめて実行するよりも、短いコードを少しずつ動かしながら結果を確認した方が理解しやすい場面が多くあります。

JupyterLabなら、説明を読みながらその場でコードを実行し、表やグラフをすぐ確認できます。

説明を読む
   ↓
Notebookのセルを実行する
   ↓
表やグラフを見る
   ↓
値や条件を少し変える
   ↓
もう一度実行する

このシリーズでJupyterLabを使う理由は、まさにこの繰り返しをしやすくするためです。

Dockerを使うので、PythonやライブラリをWindows側へ直接インストールする必要もありません。

04_docker_jupyterlab.png

基本構成は次のようにします。

time-series-part1/
├── compose.yaml
├── Dockerfile
├── requirements.txt
├── notebooks/
│   └── 01_environment.ipynb
├── data/
│   └── .gitkeep
└── src/
    └── sliding_window.py

notebooks には各Lessonで使うNotebookを置きます。

data はPart 2以降でCSVなどの時系列データを置く場所です。

src には、Notebookから何度も利用するようになった処理をPythonモジュールとして整理します。

最初からすべてをPythonファイルへ分けるのではなく、まずNotebookで動きを確かめ、再利用したくなった処理を src へ移す形で進めます。


5. Part 1 ― Fundamentals

ここからPart 1に入ります。

Part 1は、次の3章で構成されています。

  1. Python Environment
  2. What is Time Series Forecasting?
  3. Time Series as Supervised Learning

このe-learningでは、内容を3つのLessonに分けます。

Lesson 1  学習環境を準備する
     ↓
Lesson 2  時系列予測とは何か
     ↓
Lesson 3  時系列を教師あり学習へ変換する

Lesson 1 ― Docker + JupyterLabで学習環境を準備する

学習目標

このLessonでは、次のところまで進みます。

  • DockerでJupyterLabを起動する
  • WindowsのブラウザーからJupyterLabを開く
  • Notebookのセルを実行する
  • Pythonと主要ライブラリを確認する
  • 小さな時系列データを作る
  • 表とグラフで値の並びを確認する

Part 1では、まだAPIやデータベースは使いません。

まずは、Notebookのセルを実行すると結果がすぐ返ってくるという学習の流れに慣れるところから始めます。


5.1 requirements.txt

JupyterLabと、今後の時系列解析で使うライブラリを用意します。

jupyterlab
numpy
scipy
pandas
matplotlib
statsmodels
scikit-learn

主な役割は次のとおりです。

ライブラリ 主な用途
JupyterLab Notebookを使った対話的な学習環境
NumPy 配列、数値計算
SciPy 科学技術計算
pandas 時系列データの整理
Matplotlib グラフ表示
statsmodels AR、ARIMA、統計検定など
scikit-learn 機械学習、前処理、評価

Part 1ですべてのライブラリを使うわけではありません。

この先も同じDocker環境を使って学習できるよう、最初にまとめて入れておきます。


5.2 Dockerfile

FROM python:3.13-slim

# Pythonの標準出力をバッファしないようにします。
# Notebook以外からPythonを実行した場合も、print()の結果をすぐ確認できます。
ENV PYTHONUNBUFFERED=1

# .pycファイルの生成を抑止します。
# 学習用のディレクトリをホストと共有するため、不要なキャッシュファイルを減らします。
ENV PYTHONDONTWRITEBYTECODE=1

# コンテナ内の作業場所を固定します。
# notebooks、data、srcはすべてこの配下に配置します。
WORKDIR /workspace

# 依存関係だけを先にコピーします。
# ソースやNotebookだけを変更した場合にDockerのレイヤーキャッシュを利用しやすくなります。
COPY requirements.txt ./requirements.txt

# pip自体を更新してから、学習に必要なライブラリをインストールします。
# --no-cache-dirを付け、pipのダウンロードキャッシュをイメージ内に残さないようにします。
RUN python -m pip install --no-cache-dir --upgrade pip \
    && python -m pip install --no-cache-dir -r requirements.txt

# JupyterLabが利用する標準ポートです。
EXPOSE 8888

# コンテナを起動したらJupyterLabを開始します。
# --ip=0.0.0.0:
#   Dockerの外側から接続できるようにします。
# --no-browser:
#   コンテナ内ではブラウザーを起動しません。
# --allow-root:
#   この学習用コンテナではrootユーザーでJupyterLabを動かします。
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root", "--ServerApp.root_dir=/workspace"]

今回は学習用のローカル環境なので、構成を複雑にしないためコンテナ内ではrootユーザーを使います。

外部公開するJupyterLabでは、この構成をそのまま使わないようにします。


5.3 compose.yaml

services:
  timeseries:
    build:
      context: .

    # JupyterLabはコンテナ内で8888番ポートを使います。
    # ホスト側は127.0.0.1へ限定し、同じPCからだけ接続できるようにします。
    ports:
      - "127.0.0.1:8888:8888"

    # Notebook、データ、Pythonソースをホスト側へ残します。
    # コンテナを作り直しても学習内容は消えません。
    volumes:
      - ./notebooks:/workspace/notebooks
      - ./data:/workspace/data
      - ./src:/workspace/src

    working_dir: /workspace

JupyterLabの認証トークンは起動時に自動生成されます。

固定トークンや認証なしにはせず、最初はJupyterLab標準の動きのまま使います。


5.4 ディレクトリを作る

Windows 11 + WSL2 Ubuntuで作業する場合は、WSL2側で次のように準備します。

mkdir -p time-series-part1/{notebooks,data,src}
cd time-series-part1

ここへ、先ほどの

  • Dockerfile
  • compose.yaml
  • requirements.txt

を保存します。


5.5 JupyterLabを起動する

初回はイメージも作るため、次のコマンドを実行します。

docker compose up --build

起動すると、ターミナルにJupyterLabのURLが表示されます。

表示例は次のような形です。

http://127.0.0.1:8888/lab?token=xxxxxxxxxxxxxxxxxxxxxxxx

実際のトークンは起動するたびに変わることがあります。

Windows側のブラウザーで、表示されたURLを開きます。

JupyterLabの画面が表示されれば準備完了です。

2回目以降

すでにDockerイメージができていれば、通常は次だけで起動できます。

docker compose up

終了するときは Ctrl + C で停止し、必要なら次を実行します。

docker compose down

5.6 最初のNotebookを作る

JupyterLabで notebooks フォルダーを開き、Python Notebookを新しく作ります。

ファイル名は、

01_environment.ipynb

としておきます。

最初のセルで、Pythonのバージョンを確認します。

"""Lesson 1で利用しているPython環境を確認します。"""

from __future__ import annotations

import platform
import sys

# Pythonそのもののバージョンと、実行しているOS情報を表示します。
# Dockerコンテナ内で実行しているため、OSはLinuxとして表示されます。
print(f"Python   : {sys.version.split()[0]}")
print(f"Platform : {platform.platform()}")

セルを実行し、Pythonのバージョンが表示されればNotebookからコードを実行できています。


5.7 主要ライブラリを確認する

次のセルを追加します。

"""時系列予測で利用する主要ライブラリを読み込みます。"""

from __future__ import annotations

import matplotlib
import numpy as np
import pandas as pd
import scipy
import sklearn
import statsmodels

# この表は「どのバージョンを暗記するか」ではなく、
# 必要なライブラリが同じNotebookから正常に読み込めるかを確認するためのものです。
versions = pd.DataFrame(
    {
        "library": [
            "NumPy",
            "SciPy",
            "pandas",
            "Matplotlib",
            "statsmodels",
            "scikit-learn",
        ],
        "version": [
            np.__version__,
            scipy.__version__,
            pd.__version__,
            matplotlib.__version__,
            statsmodels.__version__,
            sklearn.__version__,
        ],
    }
)

versions

JupyterLabでは、最後に変数名を書くだけでも表として表示できます。

ターミナルへ文字列を出すだけの場合と違い、DataFrameの中身を表として確認しやすいのもNotebookの利点です。


5.8 小さな時系列を作る

ここで、早速小さな時系列データを作ってみます。

"""10分間隔の小さな時系列データを作成します。"""

from __future__ import annotations

import pandas as pd

# 10:00から10分間隔で5つの時刻を作ります。
# Part 1では値の変化を目で追える程度の小さなデータを使います。
time_index = pd.date_range(
    start="2026-10-06 10:00",
    periods=5,
    freq="10min",
)

# 例として、徐々に上昇していく観測値を用意します。
observed_values = [1.20, 1.35, 1.50, 1.80, 1.95]

# 時刻をIndex、観測値をSeriesとして組み合わせます。
# この形は、この先pandasで時系列を扱うときの基本になります。
series = pd.Series(
    observed_values,
    index=time_index,
    name="observed_value",
)

series.to_frame()

ここではまだ難しい処理をしていません。

大事なのは、

時刻 → 観測値

という対応が表として見えることです。


5.9 グラフで確認する

同じデータをグラフで見てみます。

"""Lesson 1の時系列を折れ線グラフで確認します。"""

from __future__ import annotations

import matplotlib.pyplot as plt

# Notebookでは、作成したグラフがセルのすぐ下に表示されます。
# markerを付けて、各観測時刻の位置も分かるようにします。
ax = series.plot(
    figsize=(9, 4),
    marker="o",
    title="Observed time series",
)

ax.set_xlabel("Time")
ax.set_ylabel("Observed value")
ax.grid(True, alpha=0.3)

plt.show()

表では、

10:00  1.20
10:10  1.35
10:20  1.50
10:30  1.80
10:40  1.95

と並んでいました。

グラフにすると、値が時間とともに上昇していることがすぐ分かります。

この「時間順に並んでいることに意味がある」という点が、次のLessonのテーマです。


5.10 少しだけ値を変えてみる

Notebookの良さを確認するために、次の値だけ変更してみます。

observed_values = [1.20, 1.35, 1.10, 1.80, 1.95]

10:20の値を 1.50 から 1.10 に変更しました。

この状態でもう一度Seriesを作り、グラフのセルを実行します。

コードを少し変える
      ↓
セルを実行する
      ↓
結果を見る
      ↓
変化を考える

この進め方を、Part 1からPart 7まで繰り返していきます。


Lesson 1 確認問題

DockerとJupyterLabを分けて使う理由を考えてみます。

問:このe-learningでDockerとJupyterLabを組み合わせる主な狙いは何でしょうか。

答えと解説を見る

DockerはPythonやライブラリの実行環境をまとめて固定するために使います。

JupyterLabは、その環境の中でコードをセル単位に実行し、表やグラフを見ながら学習するために使います。

役割を分けると、

Docker
  ↓
同じPython環境を再現する

JupyterLab
  ↓
コードを少しずつ試して理解する

という形になります。


Lesson 1 まとめ

Lesson 1では、まだ予測は行っていません。

ここで準備したのは、これから学習するための作業場所です。

Docker
  ↓
JupyterLab
  ↓
Notebook
  ↓
小さな時系列
  ↓
表とグラフで確認

次のLessonでは、先ほど作ったような時系列を使いながら、

そもそも時系列予測とは何を予測するものなのか

を考えていきます。


Lesson 2 ― 時系列予測とは何か

学習目標

このLessonでは、次の内容を理解します。

  • 時系列データと普通の表データの違い
  • 過去、現在、未来の表し方
  • Forecast Horizon
  • One-step ForecastとMulti-step Forecast
  • 時系列データで時間順序が重要な理由

6.1 値だけではなく「順番」もデータになる

次の4つの数値があるとします。

1.20
1.35
1.50
1.80

これだけなら、単なる4つの観測値です。

ところが時刻を付けると意味が変わります。

10:00  1.20
10:10  1.35
10:20  1.50
10:30  1.80

これなら、値が時間とともに上昇していることが分かります。

順番を入れ替えて、

1.80
1.20
1.50
1.35

としてしまうと、上昇しているという情報は失われます。

時系列では、観測値だけでなく、観測値が並んでいる順序も情報の一部です。

05_sequence_matters.png


6.2 t、t-1、t+1

時系列では、現在の時刻を t と表すことがよくあります。

過去                         現在                         未来

t-3      t-2      t-1         t        t+1      t+2      t+3

例えば10分間隔の観測データなら、

t-1 = 10分前
t-2 = 20分前
t-6 = 1時間前

t+1 = 10分後
t+6 = 1時間後

です。

06_timeline.png

この表し方は、この先ずっと使います。


6.3 Forecast Horizon

どこまで先を予測するかをForecast Horizonと呼びます。

10分ごとの観測なら、

Horizon = 1

で10分先、

Horizon = 6

なら1時間先になります。

現在
 │
 ├─ t+1  10分後
 ├─ t+2  20分後
 ├─ t+3  30分後
 ├─ t+4  40分後
 ├─ t+5  50分後
 └─ t+6  60分後

一般に、先の時刻になるほど不確実性は大きくなります。

そのため、予測モデルを考えるときは、

何を予測するか

だけではなく、

どこまで先を予測するか

を最初に決める必要があります。


6.4 One-step Forecast

次の1時刻だけを予測する方法です。

過去                  予測対象

t-3  t-2  t-1  t  →  t+1

10分データなら、10分先だけを予測します。

次の観測値が得られたら、その値を使ってまた次の10分先を予測できます。


6.5 Multi-step Forecast

複数時刻先までまとめて予測する方法です。

過去データ
   ↓
 t+1
 t+2
 t+3
 t+4
 t+5
 t+6

10分データなら、6ステップで1時間先まで予測できます。

河川水位で考えると、

過去の水位
   ↓
10分後
20分後
30分後
40分後
50分後
60分後

という予測になります。

One-stepとMulti-stepでは、モデルの作り方や評価方法も少し変わります。

Part 1では、まず違いが分かれば十分です。


6.6 時系列データを無条件にシャッフルしない

普通の機械学習では、データをランダムに並べ替えて学習用とテスト用へ分けることがあります。

しかし時系列では注意が必要です。

例えば、

2024年 → 学習
2025年 → テスト

であれば、過去から未来を予測しています。

一方で、未来側のデータを学習へ混ぜると、実際の予測では利用できない情報をモデルが見てしまうことがあります。

時系列では基本的に、

過去 ----------------------------→ 未来

という方向を守ります。

Train/Test分割やWalk Forward ValidationについてはPart 4で詳しく扱います。

Part 1では、時間の順序を壊さないという点を覚えておきます。


Lesson 2 確認問題

10分間隔で観測している河川水位を考えます。

現在時刻が12:00のとき、次の時刻は何時でしょうか。

  1. t-1
  2. t-6
  3. t+1
  4. t+6
答えを見る ### 答え
t-1 = 11:50
t-6 = 11:00
t+1 = 12:10
t+6 = 13:00

ここが自然に分かれば、次のLessonへ進めます。


Lesson 3 ― 時系列を教師あり学習へ変換する

学習目標

このLessonでは、Part 1で最も大切なところを扱います。

  • 時系列を入力 X と正解 y に分ける
  • Lagの考え方を理解する
  • Sliding Windowを理解する
  • Pythonで教師あり学習形式へ変換する

7.1 普通の教師あり学習

教師あり学習では、入力 X から正解 y を予測します。

入力 X
  ↓
モデル
  ↓
予測 y

例えば、

気温 + 湿度 + 曜日 → 電力需要

という問題です。

時系列も、同じ形へ変換できれば一般的な機械学習モデルで扱えるようになります。


7.2 1つ前の値から次の値を作る

次の時系列を考えます。

時刻    観測値
1       100
2       110
3       108
4       115
5       120

このままでは1本の時系列です。

そこで、1つ前の値から次の値を予測する問題へ変えます。

入力 X      正解 y
100      → 110
110      → 108
108      → 115
115      → 120

時刻表現では、

t-1 → t

です。

これで、時系列が教師あり学習の形になりました。


7.3 過去を複数使う

1つ前だけでなく、もっと前の観測値も使えます。

例えば、過去2時刻を使うなら、

t-2   t-1   →   t

となります。

先ほどの時系列なら、

100   110   → 108
110   108   → 115
108   115   → 120

です。

過去の範囲を少しずつずらしながらデータを作るため、この考え方をSliding Windowと呼びます。

07_sliding_window.png

図として表すなら、次のイメージです。

[100  110] → 108
      [110  108] → 115
            [108  115] → 120

窓が時間方向へ少しずつ移動していきます。


7.4 Window Width

何時刻分の過去を使うかを考えます。

例えば10分ごとのデータで、過去6時刻を使うなら、

Window Width = 6

です。

これは、過去1時間を入力することになります。

t-6
 t-5
  t-4
   t-3
    t-2
     t-1
      ↓
      t

Window Widthを大きくすれば情報量は増えますが、何でも長くすれば良いわけではありません。

どの程度の過去を使うかは、データの特徴や予測対象によって変わります。

この点はPart 3以降で、自己相関などを見ながら考えていきます。


7.5 PythonでSliding Windowを作る

src/sliding_window.py を作ります。

ソースを見る
"""時系列データを教師あり学習形式へ変換する最小サンプルです。

このサンプルでは、時間順に並んだ1変量の観測値から、
過去の値を説明変数X、現在または未来の値を目的変数yとして取り出します。

例:
    [100, 110, 108, 115, 120]

過去2時刻を使って現在を予測する場合:

    t-2   t-1   ->   t
    100   110        108
    110   108        115
    108   115        120
"""

from __future__ import annotations

import pandas as pd


def to_supervised(
    values: list[float],
    n_lags: int = 2,
    horizon: int = 1,
) -> pd.DataFrame:
    """時系列をスライディングウィンドウ形式へ変換します。

    Args:
        values:
            時間順に並んだ観測値です。リストの並び順を時間順として扱います。
        n_lags:
            入力特徴量として利用する過去時刻数です。
            2ならt-2とt-1の2列を作ります。
        horizon:
            予測対象として作成する時刻数です。
            1なら現在時刻tだけを作り、2ならtとt+1を作ります。

    Returns:
        過去値と予測対象を列に持つDataFrameを返します。

    Raises:
        ValueError:
            n_lagsまたはhorizonが1未満の場合に発生します。
    """

    # 0や負の値ではスライディングウィンドウを定義できないため、
    # 早い段階で入力条件を確認します。
    if n_lags < 1:
        raise ValueError("n_lagsは1以上を指定してください。")
    if horizon < 1:
        raise ValueError("horizonは1以上を指定してください。")

    # 元データをpandas.Seriesへ変換します。
    # dtypeを明示しておくと、整数と浮動小数点が混ざった場合でも
    # 時系列値の型をそろえやすくなります。
    series = pd.Series(values, name="value", dtype="float64")

    columns: dict[str, pd.Series] = {}

    # 過去側の列を作ります。
    # shift(2)なら2時刻前、shift(1)なら1時刻前の値になります。
    # rangeを逆順にしているのは、表をt-2, t-1, tの順に並べるためです。
    for lag in range(n_lags, 0, -1):
        columns[f"t-{lag}"] = series.shift(lag)

    # 現在から未来側の列を作ります。
    # step=0は現在時刻tです。
    # step=1ならshift(-1)となり、1時刻先t+1を同じ行へ並べます。
    for step in range(horizon):
        label = "t" if step == 0 else f"t+{step}"
        columns[label] = series.shift(-step)

    frame = pd.DataFrame(columns)

    # shift()を使うと、データが存在しない先頭・末尾部分にNaNができます。
    # それらは学習データとして使えないため、ここで除外します。
    return frame.dropna().reset_index(drop=True)


def main() -> None:
    """小さな時系列を教師あり学習形式へ変換して表示します。"""

    # 値の変化を追いやすいよう、Part 1では小さな人工データを使います。
    observed = [100, 110, 108, 115, 120, 125]

    # 過去2時刻を入力とし、現在時刻tを予測対象にします。
    supervised = to_supervised(
        observed,
        n_lags=2,
        horizon=1,
    )

    print(supervised.to_string(index=False))


if __name__ == "__main__":
    main()

実行します。

docker compose run --rm timeseries python src/sliding_window.py

出力は次のようになります。

  t-2   t-1     t
100.0 110.0 108.0
110.0 108.0 115.0
108.0 115.0 120.0
115.0 120.0 125.0

元の時系列は、

100 → 110 → 108 → 115 → 120 → 125

でした。

これが、

過去2時刻          現在

100  110    →      108
110  108    →      115
108  115    →      120
115  120    →      125

へ変わっています。

これなら一般的な教師あり学習の X と y に分けられます。


7.6 horizonを2にしてみる

今度は、現在だけでなく、その次の時刻まで作ってみます。

supervised = to_supervised(
    observed,
    n_lags=2,
    horizon=2,
)

すると、列は次のようになります。

t-2  t-1  t  t+1

つまり、過去2時刻から複数時刻先を扱う準備ができます。

このように、小さな引数の変更で予測問題の形そのものが変わります。

コードを書く前に、

何時刻分を入力するのか
何時刻先までを予測するのか

を決めておくことが大切です。


7.7 雨量や河川水位へ置き換えてみる

例えば10分ごとの河川水位があるとします。

10:00  1.20
10:10  1.22
10:20  1.28
10:30  1.40
10:40  1.58
10:50  1.75
11:00  1.90

過去3時刻を使って次の水位を考えるなら、

10:00  10:10  10:20  →  10:30
10:10  10:20  10:30  →  10:40
10:20  10:30  10:40  →  10:50

となります。

Sliding Windowの考え方が、そのまま実際の観測データへつながります。

雨量でも同じです。

過去6回の10分雨量
        ↓
次の10分雨量

とすれば、過去1時間の観測を使った予測問題になります。


7.8 単変量と多変量

ここまでは、1種類の値だけを使いました。

例えば水位だけなら、**単変量時系列(Univariate Time Series)**です。

時刻   水位

一方で、

時刻   雨量   水位   流量

のように複数の変数を持つ場合は、**多変量時系列(Multivariate Time Series)**になります。

例えば、

過去の雨量
過去の水位
過去の流量
      ↓
将来の水位

という問題を作れます。

ただし、未来の実測値を入力に混ぜないように注意が必要です。

予測する時点ではまだ得られていない情報を学習時だけ使ってしまうと、実運用では再現できません。

これはデータリークにつながる重要な点なので、Part 4で改めて扱います。


8. Part 1 演習

ここまで理解できたら、コードを少し変更してみます。

演習1

次のデータを使ってください。

observed = [10, 12, 14, 13, 18, 21, 20, 25]

n_lags=3 に変更して、結果を確認します。

考えるポイントは、

最初の行では、どの3つの値が入力になるか

です。


演習2

horizon=2 に変更します。

supervised = to_supervised(
    observed,
    n_lags=3,
    horizon=2,
)

列が、

t-3  t-2  t-1  t  t+1

になることを確認します。


演習3

10分雨量だと考えて、

n_lags = 6

にした場合、入力に何分間の過去データを使うことになるか考えてみます。

答えは60分、つまり1時間です。

このように、n_lags は単なる数字ではなく、実際の時間幅と対応させて考えることが大切です。


9. Part 1 確認問題

最後にPart 1全体を確認します。

問1

時系列データで、通常の表データ以上に重要になるものは何でしょうか。

答え

観測値の時間順序です。

問2

10分間隔のデータで t-6 は何分前でしょうか。

答え

60分前です。

問3

Forecast Horizonとは何でしょうか。

答え

現在からどこまで先を予測するかを表す予測期間です。

問4

Sliding Windowは何のために使うのでしょうか。

答え

時系列から過去値を入力X、現在または未来値を目的変数yとして取り出し、教師あり学習で扱える形へ変換するために使います。

問5

なぜ時系列データを無条件にランダムシャッフルしてはいけないのでしょうか。

答え

未来側の情報が学習側へ混ざり、本来の予測時点では利用できない情報をモデルが見てしまう可能性があるためです。


10. Part 1で覚えておきたいこと

Part 1では、予測モデルそのものはまだ作っていません。

しかし、時系列予測の土台になる考え方を確認しました。

重要なのは次の5点です。

1. 時系列では時間順序が重要

2. 過去・現在・未来を
   t-1 / t / t+1 で表す

3. どこまで先を予測するかを
   Forecast Horizonとして決める

4. Sliding Windowで
   時系列を教師あり学習へ変換する

5. 未来の情報を
   過去の学習へ漏らさない

08_part1_summary.png

Part 1で大切なのは、難しいモデル名を覚えることではありません。

まず、

過去のどの情報を使って、どの未来を予測するのか

をきちんと決められることです。

この土台ができていれば、この先のモデルを理解しやすくなります。


11. 次はPart 2 ― Data Preparation

次は、実際の時系列データをPythonへ読み込み、予測に使える形へ整えます。

Part 2では、次の流れを扱います。

09_part2_preview.png

Part 1では小さな人工データを使いました。

Part 2からは、もう少し実際のデータに近い形へ進みます。


参考資料

  • Jason Brownlee, Introduction to Time Series Forecasting with Python

    • Part I: Fundamentals
    • Chapter 1: Python Environment
    • Chapter 2: What is Time Series Forecasting?
    • Chapter 3: Time Series as Supervised Learning
  • Part 1 Source Zipfile


0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?