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

【第9回】Pythonで学ぶデータ分析実践 〜時系列データ分析〜

1
Last updated at Posted at 2026-07-13

第9回 時系列データ分析

はじめに

本シリーズ「Pythonで学ぶデータ分析実践」の第9回では、時系列データ分析について解説します。

株価、売上、気温、アクセス数など、時間の経過とともに測定されるデータは身の回りに多く存在します。こうした時系列データを分析し、将来の値を予測することはビジネスや研究において非常に重要です。

しかし、時系列データには「前の値が次の値に影響する」という時間依存性があるため、通常の回帰分析とは異なるアプローチが必要です。本記事では、時系列データの基本概念からARIMA・SARIMAモデルによる予測まで、実践的に解説します。

シリーズ全体の構成(全12回)

テーマ
第1回 データ分析とは
第2回 データの前処理
第3回 データの把握
第4回 相関分析
第5回 統計的推定
第6回 統計的検定
第7回 分散分析
第8回 回帰分析
第9回 時系列データ分析(本記事)
第10回 クラス分類
第11回 クラスタリング
第12回 次元削減

9-1. 時系列データとは

時系列データとは、時間の経過に沿って測定されたデータのことです。通常の回帰分析ではデータの独立性が前提ですが、時系列データでは「前の値が次の値に影響する」ため、専用の分析手法が必要です。

時系列データの例

分野 データ例 時間単位
金融 株価、為替レート 分、日
小売 売上、来店客数 日、月
気象 気温、降水量 時間、日
Web アクセス数、CVR 時間、日
製造 センサーデータ、生産量 秒、分

時系列データの4つの構成要素

時系列データは以下の4つの成分に分解できます。

成分 説明
トレンド(T) 長期的な上昇・下降の傾向 人口増加、GDP成長
季節変動(S) 一定周期で繰り返すパターン 夏にアイス売上↑、冬にコート売上↑
周期変動(C) 季節より長い不規則な波 景気循環
不規則変動(I) 予測不能なランダムな変動 突発的なイベント

$$Y_t = T_t + S_t + C_t + I_t \quad(加法モデル)$$

時系列データの基本統計量

自己共分散(Autocovariance)

同じデータの異なる時点間の関係性を測る指標です。ラグkの自己共分散は以下で定義されます。

$$\gamma(k) = \frac{1}{N}\sum_{t=1}^{N-k}(x_t - \bar{x})(x_{t+k} - \bar{x})$$

自己相関係数(ACF: Autocorrelation Function)

自己共分散を標準化した指標で、-1〜1の値をとります。

$$\rho(k) = \frac{\gamma(k)}{\gamma(0)}$$

  • ρ(k)が高い → k期前のデータと現在のデータが似ている
  • ρ(k)が低い → k期前のデータと現在は無関係

Pythonでの時系列データの基本操作

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import japanize_matplotlib

# サンプル時系列データの生成(月次売上データ)
np.random.seed(42)
dates = pd.date_range(start='2020-01-01', periods=72, freq='MS')
trend = np.linspace(100, 200, 72)
seasonal = 30 * np.sin(2 * np.pi * np.arange(72) / 12)
noise = np.random.normal(0, 10, 72)
sales = trend + seasonal + noise

ts = pd.Series(sales, index=dates, name="月次売上")

# 基本統計量
print("=== 時系列データの基本情報 ===")
print(f"期間: {ts.index[0].strftime('%Y-%m')}{ts.index[-1].strftime('%Y-%m')}")
print(f"データ数: {len(ts)}")
print(f"平均: {ts.mean():.2f}")
print(f"標準偏差: {ts.std():.2f}")

# 時系列プロット
plt.figure(figsize=(12, 4))
plt.plot(ts, color='steelblue', linewidth=1.5)
plt.xlabel("日付")
plt.ylabel("売上")
plt.title("月次売上データの推移")
plt.grid(alpha=0.3)
plt.show()

自己相関の可視化

fig, axes = plt.subplots(1, 2, figsize=(14, 4))

# 自己相関関数(ACF)
plot_acf(ts, lags=24, ax=axes[0])
axes[0].set_title("自己相関関数(ACF)")

# 偏自己相関関数(PACF)
plot_pacf(ts, lags=24, ax=axes[1])
axes[1].set_title("偏自己相関関数(PACF)")

plt.tight_layout()
plt.show()

定常性

時系列分析の多くのモデル(AR, MA, ARMA)は、データが定常であることを前提とします。

定常性 条件
定常 平均・分散が時間によらず一定 ホワイトノイズ
非定常 平均・分散が時間とともに変化 トレンドのある売上データ

定常性の確認: ADF検定(拡張ディッキー・フラー検定)

from statsmodels.tsa.stattools import adfuller

result = adfuller(ts)
print(f"=== ADF検定(定常性の検定) ===")
print(f"ADF統計量: {result[0]:.4f}")
print(f"p値: {result[1]:.6f}")
print(f"ラグ数: {result[2]}")

if result[1] < 0.05:
    print("→ 定常である(帰無仮説「単位根あり」を棄却)")
else:
    print("→ 非定常である(差分を取って定常化が必要)")

9-2. トレンド

トレンドは、データの長期的な上昇・下降傾向を表す成分です。トレンドを除去することで、季節性や短期的なパターンを分析しやすくなります。

トレンドの抽出方法

方法 特徴
移動平均 一定期間の平均でトレンドを推定
回帰分析 線形・多項式でトレンドをモデル化
季節分解 STL分解でトレンド成分を抽出
ローパスフィルタ 高周波成分を除去

移動平均によるトレンド抽出

# 移動平均(12ヶ月)
ts_ma12 = ts.rolling(window=12, center=True).mean()

plt.figure(figsize=(12, 5))
plt.plot(ts, alpha=0.7, label='元データ', color='steelblue')
plt.plot(ts_ma12, linewidth=2.5, label='12ヶ月移動平均(トレンド)', color='red')
plt.xlabel("日付")
plt.ylabel("売上")
plt.title("移動平均によるトレンドの抽出")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

時系列分解(STL分解)

# 季節分解(加法モデル)
decomposition = seasonal_decompose(ts, model='additive', period=12)

fig, axes = plt.subplots(4, 1, figsize=(12, 10), sharex=True)
decomposition.observed.plot(ax=axes[0], title='元データ(Observed)')
decomposition.trend.plot(ax=axes[1], title='トレンド(Trend)')
decomposition.seasonal.plot(ax=axes[2], title='季節変動(Seasonal)')
decomposition.resid.plot(ax=axes[3], title='残差(Residual)')

for ax in axes:
    ax.grid(alpha=0.3)
plt.tight_layout()
plt.show()

9-3. 季節性

季節性とは、一定の周期で繰り返されるパターンのことです。週次、月次、年次などさまざまな周期がありえます。

季節性の確認方法

# 月ごとの平均を計算して季節パターンを確認
monthly_pattern = ts.groupby(ts.index.month).mean()

plt.figure(figsize=(8, 5))
plt.bar(monthly_pattern.index, monthly_pattern.values, color='steelblue', alpha=0.8)
plt.xlabel("")
plt.ylabel("平均売上")
plt.title("月別平均売上(季節パターン)")
plt.xticks(range(1, 13))
plt.grid(axis='y', alpha=0.3)
plt.show()

差分による非定常性の除去

トレンドや季節性がある非定常データは、差分を取ることで定常化できます。

# 1次差分(トレンド除去)
ts_diff1 = ts.diff().dropna()

# 季節差分(季節性除去)
ts_seasonal_diff = ts.diff(12).dropna()

fig, axes = plt.subplots(3, 1, figsize=(12, 8), sharex=False)

axes[0].plot(ts)
axes[0].set_title("元データ(非定常)")
axes[0].grid(alpha=0.3)

axes[1].plot(ts_diff1)
axes[1].set_title("1次差分(トレンド除去)")
axes[1].grid(alpha=0.3)

axes[2].plot(ts_seasonal_diff)
axes[2].set_title("季節差分(周期12)")
axes[2].grid(alpha=0.3)

plt.tight_layout()
plt.show()

# 差分後の定常性検定
result = adfuller(ts_diff1)
print(f"1次差分のADF検定 p値: {result[1]:.6f}")

9-4. 自己回帰(AR)

自己回帰(AR: AutoRegressive)モデルは、過去の値そのものを用いて現在の値を予測するモデルです。「昨日の気温が高ければ、今日も高い可能性が高い」という直感に基づいています。

AR(p)モデルの数式

$$y_t = c + \alpha_1 y_{t-1} + \alpha_2 y_{t-2} + \cdots + \alpha_p y_{t-p} + \varepsilon_t$$

  • $y_t$: 時点tの値
  • $\alpha_1, \ldots, \alpha_p$: 自己回帰係数
  • $c$: 定数項
  • $\varepsilon_t$: ホワイトノイズ($N(0, \sigma^2)$に従う乱数)
  • p: 次数(何期前まで使うか)

AR(1)モデルの例

$$y_t = c + \alpha_1 y_{t-1} + \varepsilon_t$$

1期前の値のみで現在を予測する最もシンプルなARモデルです。

ARモデルの特徴

  • PACFが次数pで切断される(p期目以降で急に0に近づく)
  • ACFは徐々に減衰する
  • 過去のデータとの自己共分散が大きい場合に有効

Pythonでの実装

import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt
import japanize_matplotlib

# AR(2)モデルのデータを生成
np.random.seed(42)
n = 200
y = np.zeros(n)
y[0], y[1] = 0, 0
for t in range(2, n):
    y[t] = 0.6 * y[t-1] + 0.2 * y[t-2] + np.random.normal(0, 1)

ts_ar = pd.Series(y, name="AR(2)データ")

# ARモデルの推定(order=(p, d, q) = (2, 0, 0))
model_ar = ARIMA(ts_ar, order=(2, 0, 0))
result_ar = model_ar.fit()

print("=== AR(2)モデルの推定結果 ===")
print(result_ar.summary())

# 予測
forecast = result_ar.get_forecast(steps=30)
forecast_mean = forecast.predicted_mean
forecast_ci = forecast.conf_int()

# 可視化
plt.figure(figsize=(12, 5))
plt.plot(ts_ar[-50:], label='実測値', color='steelblue')
plt.plot(range(200, 230), forecast_mean, label='予測', color='red', linewidth=2)
plt.fill_between(range(200, 230), forecast_ci.iloc[:, 0], forecast_ci.iloc[:, 1],
                 alpha=0.2, color='red', label='95%信頼区間')
plt.xlabel("時点")
plt.ylabel("")
plt.title("AR(2)モデルによる予測")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

9-5. 移動平均(MA)

移動平均(MA: Moving Average)モデルは、過去の予測誤差(残差)を用いて現在の値を予測するモデルです。

MA(q)モデルの数式

$$y_t = c + \varepsilon_t + \theta_1 \varepsilon_{t-1} + \theta_2 \varepsilon_{t-2} + \cdots + \theta_q \varepsilon_{t-q}$$

  • $\theta_1, \ldots, \theta_q$: 移動平均係数
  • $\varepsilon_t$: 時点tのホワイトノイズ
  • q: 次数(何期前の誤差まで使うか)

MAモデルの特徴

  • ACFが次数qで切断される(q期目以降で急に0に近づく)
  • PACFは徐々に減衰する
  • 短期的なショックの影響がデータに残る場合に有効

ARモデルとMAモデルの見分け方

特徴 ARモデル MAモデル
ACF 徐々に減衰 q期で切断
PACF p期で切断 徐々に減衰
意味 過去の値で予測 過去の誤差で予測

Pythonでの実装

# MA(2)モデルのデータを生成
np.random.seed(42)
n = 200
eps = np.random.normal(0, 1, n)
y_ma = np.zeros(n)
for t in range(2, n):
    y_ma[t] = eps[t] + 0.7 * eps[t-1] + 0.3 * eps[t-2]

ts_ma = pd.Series(y_ma, name="MA(2)データ")

# MAモデルの推定(order=(0, 0, 2))
model_ma = ARIMA(ts_ma, order=(0, 0, 2))
result_ma = model_ma.fit()

print("=== MA(2)モデルの推定結果 ===")
print(f"θ1 = {result_ma.params[1]:.4f}")
print(f"θ2 = {result_ma.params[2]:.4f}")
print(f"AIC = {result_ma.aic:.2f}")

9-6. ARMA

ARMA(AutoRegressive Moving Average)モデルは、ARモデルとMAモデルを組み合わせたモデルです。過去のデータ(AR部分)と過去の誤差(MA部分)の両方を考慮して予測を行います。

ARMA(p, q)モデルの数式

$$y_t = c + \sum_{i=1}^{p}\alpha_i y_{t-i} + \varepsilon_t + \sum_{j=1}^{q}\theta_j \varepsilon_{t-j}$$

ARMAモデルの適用条件

  • データが定常であること(平均・分散が時間によらず一定)
  • 非定常データには差分を取ってから適用するか、ARIMAモデルを使用

次数(p, q)の決定方法

方法 説明
ACF/PACF ACFの切断→q、PACFの切断→pの手がかり
AIC/BIC 複数の(p,q)を試し、AIC/BICが最小のモデルを選択
auto_arima 自動で最適な次数を探索

Pythonでの実装

# ARMA(2,1)モデル(定常データに適用)
# ARIMAのorder=(p, 0, q)として指定
model_arma = ARIMA(ts_ar, order=(2, 0, 1))
result_arma = model_arma.fit()

print("=== ARMA(2,1)モデルの推定結果 ===")
print(f"AR係数: {result_arma.arparams}")
print(f"MA係数: {result_arma.maparams}")
print(f"AIC: {result_arma.aic:.2f}")
print(f"BIC: {result_arma.bic:.2f}")

AICによるモデル選択

import warnings
warnings.filterwarnings('ignore')

# 複数のARMAモデルを比較
results = []
for p in range(0, 4):
    for q in range(0, 4):
        try:
            model = ARIMA(ts_ar, order=(p, 0, q))
            fit = model.fit()
            results.append({"p": p, "q": q, "AIC": fit.aic, "BIC": fit.bic})
        except:
            continue

df_results = pd.DataFrame(results).sort_values("AIC")
print("=== AICによるモデル比較(上位5件) ===")
print(df_results.head().to_string(index=False))

9-7. ARIMA

ARIMA(AutoRegressive Integrated Moving Average)モデルは、ARMAモデルに**差分化(I: Integrated)**を加えたもので、非定常データ(トレンドのあるデータ)にも対応できます。

ARIMA(p, d, q)のパラメータ

パラメータ 意味 役割
p AR次数 何期前までの値を使うか
d 差分次数 何回差分を取るか(非定常→定常化)
q MA次数 何期前までの誤差を使うか

ARIMAモデルの適用場面

  • 非季節的トレンドのあるデータ
  • 売上、株価、経済指標など長期的傾向を持つデータ
  • 季節性がない(または弱い)時系列データ

Pythonでの実装

import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.stattools import adfuller
import matplotlib.pyplot as plt
import japanize_matplotlib

# トレンドのある非定常データの生成
np.random.seed(42)
n = 120
trend = np.linspace(100, 250, n)
noise = np.random.normal(0, 10, n)
ts_nonstat = pd.Series(trend + noise,
                        index=pd.date_range('2015-01', periods=n, freq='MS'),
                        name="売上")

# 定常性の確認
result = adfuller(ts_nonstat)
print(f"=== 元データのADF検定 ===")
print(f"p値: {result[1]:.6f}{'定常' if result[1] < 0.05 else '非定常'}")

# 1次差分後の定常性
ts_diff = ts_nonstat.diff().dropna()
result_diff = adfuller(ts_diff)
print(f"\n=== 1次差分後のADF検定 ===")
print(f"p値: {result_diff[1]:.6f}{'定常' if result_diff[1] < 0.05 else '非定常'}")

# ARIMA(1,1,1)モデルの構築
model = ARIMA(ts_nonstat, order=(1, 1, 1))
result_arima = model.fit()

print(f"\n=== ARIMA(1,1,1)モデル ===")
print(f"AIC: {result_arima.aic:.2f}")
print(f"BIC: {result_arima.bic:.2f}")
print(result_arima.summary())

予測と可視化

# 12ヶ月先まで予測
forecast = result_arima.get_forecast(steps=12)
forecast_mean = forecast.predicted_mean
forecast_ci = forecast.conf_int()

plt.figure(figsize=(12, 5))
plt.plot(ts_nonstat, label='実測値', color='steelblue', linewidth=1.5)
plt.plot(forecast_mean, label='予測値', color='red', linewidth=2)
plt.fill_between(forecast_ci.index,
                 forecast_ci.iloc[:, 0], forecast_ci.iloc[:, 1],
                 alpha=0.2, color='red', label='95%信頼区間')
plt.xlabel("日付")
plt.ylabel("売上")
plt.title("ARIMA(1,1,1)モデルによる売上予測")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

パラメータの自動最適化

import itertools
import warnings
warnings.filterwarnings('ignore')

# グリッドサーチでAICが最小のパラメータを探索
best_aic = np.inf
best_order = None

for p in range(0, 4):
    for d in range(0, 3):
        for q in range(0, 4):
            try:
                model = ARIMA(ts_nonstat, order=(p, d, q))
                fit = model.fit()
                if fit.aic < best_aic:
                    best_aic = fit.aic
                    best_order = (p, d, q)
            except:
                continue

print(f"=== 最適パラメータ(AIC最小) ===")
print(f"order: {best_order}")
print(f"AIC: {best_aic:.2f}")

# 最適モデルで再推定
best_model = ARIMA(ts_nonstat, order=best_order).fit()
print(f"\n最適モデルのサマリー:")
print(best_model.summary())

pmdarima による自動ARIMA

pmdarimaライブラリのauto_arimaを使うと、最適なパラメータを自動で探索できます。

# pip install pmdarima
from pmdarima import auto_arima

# 自動ARIMAパラメータ選択
auto_model = auto_arima(ts_nonstat,
                         start_p=0, max_p=5,
                         start_q=0, max_q=5,
                         d=None,  # 自動で差分次数を決定
                         seasonal=False,
                         stepwise=True,
                         trace=True)

print(f"\n=== auto_arima 結果 ===")
print(auto_model.summary())

9-8. SARIMA

SARIMA(Seasonal ARIMA)モデルは、ARIMAモデルに季節性の成分を加えたモデルです。季節的なパターンを持つ時系列データ(売上の年末増加、夏のビール消費増など)をモデル化する場合に使用します。

SARIMAのパラメータ

SARIMAは非季節性パラメータ季節性パラメータの2組を指定します。

$$SARIMA(p, d, q)(P, D, Q, s)$$

パラメータ 種類 意味
p 非季節性 AR次数
d 非季節性 差分次数
q 非季節性 MA次数
P 季節性 季節AR次数
D 季節性 季節差分次数
Q 季節性 季節MA次数
s 季節性 季節周期(12=月次、7=週次、4=四半期)

SARIMAモデルの適用場面

  • 明確な季節パターンがあるデータ
  • 月次売上データ(12ヶ月周期)
  • 日次アクセスデータ(7日周期)
  • 四半期決算データ(4期周期)

Pythonでの実装

import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX
import matplotlib.pyplot as plt
import japanize_matplotlib

# 季節性のある時系列データの生成
np.random.seed(42)
n = 96  # 8年分の月次データ
dates = pd.date_range(start='2017-01-01', periods=n, freq='MS')
trend = np.linspace(100, 180, n)
seasonal = 25 * np.sin(2 * np.pi * np.arange(n) / 12) + 15 * np.cos(2 * np.pi * np.arange(n) / 12)
noise = np.random.normal(0, 8, n)
ts_seasonal = pd.Series(trend + seasonal + noise, index=dates, name="月次売上")

# データの可視化
plt.figure(figsize=(12, 5))
plt.plot(ts_seasonal, color='steelblue', linewidth=1.5)
plt.xlabel("日付")
plt.ylabel("売上")
plt.title("季節性のある月次売上データ")
plt.grid(alpha=0.3)
plt.show()

# 学習データとテストデータの分割
train = ts_seasonal[:'2023-12']
test = ts_seasonal['2024-01':]

print(f"学習データ: {train.index[0].strftime('%Y-%m')}{train.index[-1].strftime('%Y-%m')} ({len(train)}件)")
print(f"テストデータ: {test.index[0].strftime('%Y-%m')}{test.index[-1].strftime('%Y-%m')} ({len(test)}件)")

SARIMAモデルの構築

# SARIMAモデルの推定
# SARIMA(1,1,1)(1,1,1,12) - 月次データ(周期12)
model_sarima = SARIMAX(train,
                        order=(1, 1, 1),
                        seasonal_order=(1, 1, 1, 12),
                        enforce_stationarity=False,
                        enforce_invertibility=False)
result_sarima = model_sarima.fit(disp=False)

print("=== SARIMA(1,1,1)(1,1,1,12)モデル ===")
print(f"AIC: {result_sarima.aic:.2f}")
print(f"BIC: {result_sarima.bic:.2f}")
print(result_sarima.summary())

予測と評価

# テスト期間の予測
forecast = result_sarima.get_forecast(steps=len(test))
forecast_mean = forecast.predicted_mean
forecast_ci = forecast.conf_int()

# 可視化
plt.figure(figsize=(14, 6))
plt.plot(train[-24:], label='学習データ', color='steelblue', linewidth=1.5)
plt.plot(test, label='実測値(テスト)', color='green', linewidth=1.5, linestyle='--')
plt.plot(forecast_mean, label='予測値', color='red', linewidth=2)
plt.fill_between(forecast_ci.index,
                 forecast_ci.iloc[:, 0], forecast_ci.iloc[:, 1],
                 alpha=0.2, color='red', label='95%信頼区間')
plt.xlabel("日付")
plt.ylabel("売上")
plt.title("SARIMAモデルによる売上予測")
plt.legend()
plt.grid(alpha=0.3)
plt.show()

# 予測精度の評価
from sklearn.metrics import mean_squared_error, mean_absolute_error

rmse = np.sqrt(mean_squared_error(test, forecast_mean))
mae = mean_absolute_error(test, forecast_mean)
mape = np.mean(np.abs((test - forecast_mean) / test)) * 100

print(f"\n=== 予測精度 ===")
print(f"RMSE: {rmse:.2f}")
print(f"MAE: {mae:.2f}")
print(f"MAPE: {mape:.2f}%")

auto_arimaによるSARIMAの自動最適化

from pmdarima import auto_arima

# 季節性ありの自動ARIMA
auto_model = auto_arima(train,
                         start_p=0, max_p=3,
                         start_q=0, max_q=3,
                         d=None,
                         start_P=0, max_P=2,
                         start_Q=0, max_Q=2,
                         D=None,
                         seasonal=True,
                         m=12,  # 季節周期
                         stepwise=True,
                         trace=True)

print(f"\n=== auto_arima(季節性あり)の結果 ===")
print(auto_model.summary())

# 予測
forecast_auto = auto_model.predict(n_periods=len(test), return_conf_int=True)

補足:時系列分析の実践的なポイント

モデル選択のフロー

データに季節性はあるか?
├── あり → SARIMA(季節周期sを設定)
└── なし
    ├── データは定常か?
    │   ├── はい → ARMA(d=0)
    │   └── いいえ → ARIMA(差分dを設定)
    └── トレンドの型は?
        ├── 線形 → d=1で十分なことが多い
        └── 二次的 → d=2を検討

残差診断

良いモデルの残差はホワイトノイズ(ランダム)であるべきです。

# 残差診断
residuals = result_sarima.resid

fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# 残差のプロット
axes[0,0].plot(residuals)
axes[0,0].set_title("残差の推移")
axes[0,0].axhline(0, color='red', linestyle='--')

# 残差のヒストグラム
axes[0,1].hist(residuals, bins=20, edgecolor='black', alpha=0.7, density=True)
axes[0,1].set_title("残差のヒストグラム")

# ACF
from statsmodels.graphics.tsaplots import plot_acf
plot_acf(residuals, lags=24, ax=axes[1,0])
axes[1,0].set_title("残差のACF")

# Q-Qプロット
from scipy import stats
stats.probplot(residuals, plot=axes[1,1])
axes[1,1].set_title("残差のQ-Qプロット")

plt.tight_layout()
plt.show()

# Ljung-Box検定(残差が白色雑音かどうか)
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_result = acorr_ljungbox(residuals, lags=[12], return_df=True)
print(f"\n=== Ljung-Box検定 ===")
print(lb_result)
if lb_result['lb_pvalue'].values[0] > 0.05:
    print("→ 残差はホワイトノイズ(モデルは適切)")
else:
    print("→ 残差に自己相関あり(モデルの改善が必要)")

時系列分析でよくある注意点

注意点 説明
過学習 パラメータを増やしすぎると過学習する。AIC/BICで抑制
データ漏洩 テストデータの情報が学習に混入しないようにする
外れ値 突発的なイベント(コロナ禍など)の影響を考慮
構造変化 途中でデータの性質が変わった場合、分割してモデル化
予測の不確実性 予測期間が長くなるほど信頼区間は広がる

まとめ

本記事では、時系列データ分析として以下の内容を解説しました。

項目 ポイント
時系列データとは 時間依存性があり、特別な分析手法が必要
トレンド 長期的な傾向。移動平均やSTL分解で抽出
季節性 一定周期のパターン。差分で除去可能
AR 過去の値で予測。PACFで次数pを決定
MA 過去の誤差で予測。ACFで次数qを決定
ARMA AR+MA。定常データに適用
ARIMA ARMA+差分化。非定常データに対応
SARIMA ARIMA+季節成分。季節パターンのあるデータに対応

時系列分析のチェックリスト

  • データの時間的な推移を可視化したか
  • トレンドと季節性の有無を確認したか
  • 定常性を検定したか(ADF検定)
  • ACF/PACFでモデルの次数の見当をつけたか
  • AIC/BICで複数モデルを比較したか
  • 残差診断を行い、モデルの妥当性を確認したか
  • テストデータで予測精度を評価したか
  • 信頼区間を含めて予測結果を報告したか

シリーズ記事一覧

次回の第10回では、データを分類するクラス分類について解説します。決定木、ランダムフォレスト、ロジスティック回帰などの分類手法と、その評価方法を学びます。

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