状態空間モデルとは?時系列データ解析の基礎を理解して実装する

時系列データを扱う際、自己回帰モデル(ARモデル)のように過去の観測値だけで将来を予測する手法は、単一の周期を持つデータには有効です。しかし、複雑な動的システムでは、直接観測できない「内部状態」が存在し、それが観測データを生み出していると考えるほうが自然な場合があります。

状態空間モデルは、このような「隠れた内部状態」と「観測データ」の関係を数学的に定式化するフレームワークです。カルマンフィルタや粒子フィルタの基礎となる重要な概念であり、制御工学、信号処理、経済学など幅広い分野で活用されています。

本記事の内容

  • 状態空間モデルの定義と直感的な理解
  • 観測方程式・状態方程式の数学的な導出
  • Pythonでのシミュレーションと可視化

状態空間モデルとは

状態空間モデルとは、時刻 $t$ におけるシステムの内部状態 $\bm{z}_t$ と、観測される量 $\bm{x}_t$ の関係を2つの方程式で記述するモデルです。

イメージとしては、私たちが直接観測できるのは $\bm{x}_t$ だけですが、その背後には隠れた状態 $\bm{z}_t$ があり、それが時間とともに変化しているという構造を仮定します。

数学的定義

状態空間モデルは、以下の2つの方程式で構成されます。

状態方程式(遷移方程式)

$$ \bm{z}_t = \bm{A} \bm{z}_{t-1} + \bm{w}_t $$

ここで、$\bm{z}_t \in \mathbb{R}^m$ は時刻 $t$ における状態ベクトル、$\bm{A} \in \mathbb{R}^{m \times m}$ は状態遷移行列、$\bm{w}_t \sim \mathcal{N}(\bm{0}, \bm{Q})$ はシステムノイズ(プロセスノイズ)です。

この方程式は、「現在の状態は前の時刻の状態に行列 $\bm{A}$ を掛けた線形変換にノイズを加えたもの」であることを意味しています。

観測方程式

$$ \bm{x}_t = \bm{C} \bm{z}_t + \bm{v}_t $$

ここで、$\bm{x}_t \in \mathbb{R}^M$ は時刻 $t$ における観測ベクトル、$\bm{C} \in \mathbb{R}^{M \times m}$ は観測行列、$\bm{v}_t \sim \mathcal{N}(\bm{0}, \bm{R})$ は観測ノイズです。

この方程式は、「観測値は内部状態を行列 $\bm{C}$ で射影し、観測ノイズを加えたもの」であることを意味しています。

ノイズの仮定

状態空間モデルでは、2つのノイズに以下の仮定を置きます。

$$ \bm{w}_t \sim \mathcal{N}(\bm{0}, \bm{Q}), \quad \bm{v}_t \sim \mathcal{N}(\bm{0}, \bm{R}) $$

さらに、$\bm{w}_t$ と $\bm{v}_t$ は互いに独立であると仮定します。

$$ E[\bm{w}_t \bm{v}_s^\top] = \bm{0} \quad \forall t, s $$

状態方程式の導出

状態方程式がどのように時間発展を記述するか、具体的に展開してみましょう。初期状態 $\bm{z}_0$ から出発すると、各時刻での状態は次のようになります。

$$ \begin{align} \bm{z}_1 &= \bm{A} \bm{z}_0 + \bm{w}_1 \\ \bm{z}_2 &= \bm{A} \bm{z}_1 + \bm{w}_2 = \bm{A}^2 \bm{z}_0 + \bm{A} \bm{w}_1 + \bm{w}_2 \\ \bm{z}_t &= \bm{A}^t \bm{z}_0 + \sum_{k=1}^{t} \bm{A}^{t-k} \bm{w}_k \end{align} $$

この式から、状態 $\bm{z}_t$ は初期状態 $\bm{z}_0$ の影響( $\bm{A}^t \bm{z}_0$ )と、過去のノイズの累積効果( $\sum_{k=1}^{t} \bm{A}^{t-k} \bm{w}_k$ )の和で表されることがわかります。

観測の同時分布

観測系列 $\bm{x}_1, \bm{x}_2, \dots, \bm{x}_T$ の同時確率は、マルコフ性を利用して次のように因数分解できます。

$$ p(\bm{x}_1, \dots, \bm{x}_T) = p(\bm{x}_1) \prod_{t=2}^{T} p(\bm{x}_t \mid \bm{x}_1, \dots, \bm{x}_{t-1}) $$

状態空間モデルの重要な性質は、状態 $\bm{z}_t$ が与えられれば、観測 $\bm{x}_t$ は過去の観測から条件付き独立になることです。

$$ p(\bm{x}_t \mid \bm{z}_t) = \mathcal{N}(\bm{C} \bm{z}_t, \bm{R}) $$

具体例:1次元の等速運動モデル

状態空間モデルの直感を掴むために、位置と速度を状態とする1次元の等速運動モデルを考えます。

状態ベクトルを $\bm{z}_t = \begin{pmatrix} p_t \\ v_t \end{pmatrix}$ (位置 $p_t$ と速度 $v_t$ )とします。

状態遷移行列は、等速運動の物理法則 $p_t = p_{t-1} + v_{t-1} \Delta t$ に基づいて次のように設定します。

$$ \bm{A} = \begin{pmatrix} 1 & \Delta t \\ 0 & 1 \end{pmatrix} $$

観測行列は、位置のみが観測可能な場合、次のようになります。

$$ \bm{C} = \begin{pmatrix} 1 & 0 \end{pmatrix} $$

Pythonでの実装

上記の等速運動モデルをPythonでシミュレーションしてみましょう。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

# パラメータ設定
T = 100          # 時間ステップ数
dt = 1.0         # 時間間隔
q = 0.1          # プロセスノイズの標準偏差
r = 1.0          # 観測ノイズの標準偏差

# 状態遷移行列(等速運動モデル)
A = np.array([[1, dt],
              [0, 1]])

# 観測行列(位置のみ観測)
C = np.array([[1, 0]])

# ノイズの共分散行列
Q = q**2 * np.array([[dt**3/3, dt**2/2],
                      [dt**2/2, dt]])
R = np.array([[r**2]])

# 真の状態と観測のシミュレーション
z_true = np.zeros((T, 2))  # 状態 [位置, 速度]
x_obs = np.zeros((T, 1))   # 観測値

# 初期状態
z_true[0] = [0, 1.0]  # 位置0、速度1でスタート

for t in range(1, T):
    # プロセスノイズの生成
    w = np.random.multivariate_normal([0, 0], Q)
    # 状態の遷移
    z_true[t] = A @ z_true[t-1] + w

for t in range(T):
    # 観測ノイズの生成
    v = np.random.normal(0, r)
    # 観測値の生成
    x_obs[t] = C @ z_true[t] + v

# 可視化
fig, axes = plt.subplots(2, 1, figsize=(10, 8))

# 位置のプロット
axes[0].plot(range(T), z_true[:, 0], label='True Position', linewidth=2)
axes[0].scatter(range(T), x_obs[:, 0], s=10, c='red', alpha=0.5, label='Observations')
axes[0].set_xlabel('Time step')
axes[0].set_ylabel('Position')
axes[0].set_title('State Space Model: Position')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 速度のプロット
axes[1].plot(range(T), z_true[:, 1], label='True Velocity', linewidth=2, color='green')
axes[1].set_xlabel('Time step')
axes[1].set_ylabel('Velocity')
axes[1].set_title('State Space Model: Velocity (Hidden State)')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

このコードでは、等速運動モデルに基づいて真の状態(位置と速度)をシミュレーションし、観測ノイズを加えた観測値を生成しています。上段のグラフでは、青い線が真の位置、赤い点がノイズの乗った観測値を表しています。下段のグラフでは、直接観測できない速度(隠れ状態)の変化を示しています。

まとめ

本記事では、状態空間モデルの基本的な構造と数学的定義について解説しました。

  • 状態空間モデルは、状態方程式と観測方程式の2つの方程式からなるフレームワークである
  • 状態方程式は内部状態の時間発展を、観測方程式は状態から観測値への変換を記述する
  • ノイズは正規分布に従うと仮定し、プロセスノイズと観測ノイズは互いに独立である
  • 等速運動モデルのように、物理法則に基づいて行列 $\bm{A}$, $\bm{C}$ を設計できる

状態空間モデルの枠組みを理解することで、カルマンフィルタによる状態推定や、粒子フィルタによる非線形・非ガウスモデルへの拡張が自然に理解できるようになります。