Rの関数から dlmSmooth {dlm} を確認します。
本ポストはこちらの続きです。

Rのパッケージ:dlm
const typesetMath = (el) => { if (window.MathJax) { // MathJax Typeset window.MathJax.typeset(); } else if (window.katex...
dlmSmooth
関数の引数
dlmSmooth
関数は、dlm
パッケージにおいて平滑化(Smoothing)を実行するための中心的な関数です。
フィルタリングが各時点t
までのデータを用いてその時点の状態(レベル、トレンドなど)を推定するのに対し、平滑化は全ての観測期間(t=1
からt=T
まで)のデータを用いて、過去の各時点t
の状態を再推定する処理です。
それにより、フィルタリングよりも多くの情報を利用できるため、ノイズの影響がさらに除去され、より滑らかで確からしい状態の推定値を得ることができます。
以下に、関数の引数を詳細に説明します。
library(dlm)
args(dlmSmooth)
function (y, ...)
NULL
y
- 分析対象の時系列データを指定します。後述する「パターン1」のように、
dlm
モデルオブジェクトを直接dlmSmooth
に渡す際に使用します。 - データ形式:
ts
オブジェクト、数値ベクトル (vector
)、または行列 (matrix
) を指定できます。 - 省略可能な場合: 後述する「パターン2」のように、
dlmFilter
関数の結果(dlmFiltered
オブジェクト)をdlmSmooth
に渡す場合、そのオブジェクト内に既にデータy
の情報が含まれているため、この引数は不要です。
...
-
dlmSmooth
関数の挙動を決定する部分です。ここには、dlm
モデルオブジェクト、またはdlmFilter
関数の実行結果のいずれかを渡します。
パターン1:dlm
オブジェクトを渡す場合 (dlmSmooth(y, mod, ...)
)
この使い方では、引数y
にデータ、そして...
の部分にdlm
オブジェクトをmod
という名前(または名前なし)で渡します。
-
mod
:dlm
クラスのオブジェクトを指定します。- この
mod
オブジェクトは、観測ノイズの分散V
やシステムノイズの共分散行列W
といった、全てのパラメータが具体的な数値として設定済みである必要があります。通常、dlmMLE
で推定したパラメータを使って構築したモデルをここに渡します。 - この形式で呼び出された場合、
dlmSmooth
はまず内部でdlmFilter(y, mod)
を実行してフィルタリングを行い、その結果を用いて平滑化計算を行います。ですので、一行でフィルタリングから平滑化までを実行していることになります。
- この
パターン2:dlmFiltered
オブジェクトを渡す場合 (dlmSmooth(object, ...)
)
この使い方では、dlmFilter
関数の実行結果であるdlmFiltered
オブジェクトを...
の部分に渡します。
-
object
:dlmFilter
関数の返り値(dlmFiltered
クラスのオブジェクト)を指定します。- この方法は、既にフィルタリングを実行済みの場合、フィルタリングの結果と平滑化の結果の両方を個別に評価したい場合に有用です。
- この場合、
dlmFiltered
オブジェクト内にデータy
やモデルの情報が含まれているため、引数y
を明示的に指定する必要はありません。
戻り値について
dlmSmooth
関数は、dlmSmoothed
クラスのリストを返します。このリストには多くの情報が含まれていますが、特に重要なのは以下の2つです。
-
s
: 各時点における平滑化された状態ベクトルの時系列(行列)です。- 行列の各行が時点、各列が状態(例:1列目がレベル、2列目がトレンド)に対応します。
- これが分析の主目的となる結果であり、時系列の成分分解などに使用されます。
-
S
: 各時点における、平滑化された状態ベクトルの共分散行列のリストです。- これは、平滑化された状態推定値の不確実性(分散)を表します。状態の信頼区間を計算する際に使用できます。
コードによる具体例
サンプルデータとモデルを用いて、上記2つのパターンの使い方を示します。
# サンプルデータとモデルの準備
<- 20250930
seed set.seed(seed)
<- ts(cumsum(rnorm(50, sd = 2)) + rnorm(50, sd = 5), start = 2020)
y_sample
# モデル構築関数 (状態が1つのモデル)
<- function(par) {
build_func dlmModPoly(order = 1, dV = exp(par[1]), dW = exp(par[2]))
}
# パラメータの最尤推定
<- dlmMLE(y_sample, parm = c(0, 0), build = build_func)
mle_fit
# 推定されたパラメータで最終モデルを構築
<- build_func(mle_fit$par)
final_model
# --- パターン1:データ(y)とモデル(mod)を直接渡す ---
<- dlmSmooth(y = y_sample, mod = final_model)
smoothed_result1
# as.matrix()でオブジェクトを行列に変換してから要素を抽出します。
# また、smoothed_result1$s には t=0 の初期状態も含まれるため、
# [-1, ] でその最初の行を除外しています。
<- as.matrix(smoothed_result1$s)
s_matrix <- ts(s_matrix[-1, 1], start = start(y_sample), frequency = frequency(y_sample))
smooth_level1
cat("--- パターン1で得られた平滑化系列の一部を確認 ---\n")
print(head(smooth_level1))
# --- パターン2:dlmFilterの結果を渡す ---
<- dlmFilter(y = y_sample, mod = final_model)
filtered_result <- dlmSmooth(filtered_result)
smoothed_result2
<- as.matrix(smoothed_result2$s)
s_matrix2 <- ts(s_matrix2[-1, 1], start = start(y_sample), frequency = frequency(y_sample))
smooth_level2
cat("\n--- パターン2で得られた平滑化系列の一部を確認 ---\n")
print(head(smooth_level2))
# --- 結果の可視化 ---
plot(y_sample,
type = "p", pch = 16, col = "grey",
main = "観測データと平滑化系列",
xlab = "年", ylab = "値"
)lines(smooth_level1, col = "firebrick", lwd = 2, lty = 1)
lines(smooth_level2, col = "blue", lwd = 2, lty = "dashed")
legend("topleft",
legend = c("観測値", "平滑化系列 (パターン1)", "平滑化系列 (パターン2)"),
col = c("grey", "firebrick", "blue"),
lty = c(NA, 1, 2),
pch = c(16, NA, NA),
lwd = 2,
bty = "n"
)grid()
cat("\n--- 両パターンの結果は一致しているか ---\n")
print(all.equal(target = smooth_level1, current = smooth_level2))
--- パターン1で得られた平滑化系列の一部を確認 ---
Time Series:
Start = 2020
End = 2025
Frequency = 1
[1] 2.470889 3.133549 2.464554 3.767059 5.041644 8.113619
--- パターン2で得られた平滑化系列の一部を確認 ---
Time Series:
Start = 2020
End = 2025
Frequency = 1
[1] 2.470889 3.133549 2.464554 3.767059 5.041644 8.113619
--- 両パターンの結果は一致しているか ---
[1] TRUE
上記のコードと Figure 1 が示すように、パターン1
とパターン2
は全く同じ平滑化結果を生成します。どちらを使うかは、分析のフローや好みに応じて選択できます。一般的には、フィルタリングの結果も利用したい場合はパターン2
が、平滑化の結果だけが目的であればパターン1
が手軽です。
以上です。