SSM (State-Space Model)과 관련하여 KF (Kalman Filtering) 기술을 통해 스플라인을 사용하는 방법에 대해 설명합니다. 일부 스플라인 모델이 SSM으로 표현되고 KF로 계산 될 수 있다는 사실은 1980-1990 년에 CF Ansley와 R. Kohn에 의해 밝혀졌습니다. 추정 된 기능과 그 파생어는 관측치에 대한 상태의 기대치입니다. 이러한 추정값은 SSM을 사용할 때 일상적인 작업 인 고정 간격 스무딩 을 사용하여 계산됩니다 .
간단히하기 위해, 시점에서 관측이 이루어지고 에서
의 관측 번호 는
차수를 단 하나의 도함수를 포함 한다고 가정합니다. . 모델의 관측 부분은
로 여기서 는 관찰되지 않은 참 함수를 나타내고
는 유도 차수 에 따라 분산 가있는 가우스 오차입니다 . (연속 시간) 전이 방정식은 일반적인 형태를 취합니다.
t1<t2<⋯<tnktkd k { 0 ,dk{0,1,2}y(tk)=f[dk](tk)+ε(tk)(O1)
f(t)ε ( t k ) H ( t k ) d kε(tk)H(tk)dkddtα(t)=Aα(t)+η(t)(T1)
여기서 관찰되지 상태 벡터이며
공분산을 갖는 가우시안 백색 잡음이다 상기 독립적 인 것으로 가정 관측 노이즈 r.vs . 스플라인을 설명하기 위해
1 차 도함수 를 쌓아서 얻은 상태 , 즉 . 전환은
α(t)η(t)Qε(tk)mα(t):=[f(t),f[1](t),…,f[m−1](t)]⊤⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢f[1](t)f[2](t)⋮f[m−1](t)f[m](t)⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢00⋮010…01⋱10⎤⎦⎥⎥⎥⎥⎥⎥⎥⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢f(t)f[1](t)⋮f[m−2](t)f[m−1](t)⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥+⎡⎣⎢⎢⎢⎢⎢⎢⎢00⋮0η(t)⎤⎦⎥⎥⎥⎥⎥⎥⎥
그리고 우리 는 차수 (및 차수
) 의 다항식 스플라인 을 얻습니다 . 는 일반적인 입방 스플라인에 해당 하지만2m2m-1m=2>(1 개) , Y ( t에서 K ) 2m2m−1m=2>1. 고전적인 SSM 형식을 고수하기 위해 (O1)을
관측 행렬 여기서 상기 적합한 유도체를 집어 및 분산 의
에 따라 선택된다 . 따라서 여기서 ,
및 . 마찬가지로y(tk)=Z(tk)α(tk)+ε(tk),(O2)
Z(tk)α(tk)H(tk)ε(tk)dkZ(tk)=Z⋆dk+1Z⋆1:=[1,0,…,0]Z⋆2:=[0,1,…0]Z⋆3:=[0,0,1,0,…]H(tk)=H⋆dk+1 H ⋆ 1 H ⋆ 2 H ⋆ 3세 대한 편차를 ,
및 . H⋆1H⋆2H⋆3
전환이 연속 시간이지만 KF는 실제로 표준 이산 시간 입니다. 사실, 우리는 것이다 배에 연습 초점 우리가 관찰을, 어디서 우리가 파생 상품을 추정 할 수 있습니다. 우리는 세트 걸릴 수 있습니다 번이 두 집합의 합집합을하고에서 관찰한다고 가정 할 누락 될 수 있습니다 : 이것은 추정 할 수 어떤 시간에 파생 상품을
에 관계없이 관찰의 존재. 이산 SSM을 도출해야합니다.t{tk}tkmtk
우리는 불연속 시간에 인덱스를 사용 하고 등을 위해 를
작성 합니다. 불연속 SSM은 형식을 취합니다.
여기서 행렬 및 (T1)로부터 유도되고 (O2)의 분산 상태 주어진다
은 제공했습니다αkα(tk)αk+1yk=Tkαk+η⋆k=Zkαk+εk(DT)
TkQ⋆k:=Var(η⋆k)εkHk=H⋆dk+1ykTk=exp{δkA}=[ 1 δ 1 k누락되지 않았습니다. 일부 대수를 사용하여 불연속 SSM에 대한 전이 행렬을 찾을 수 있습니다.
에 대한 . 마찬가지로 이산 시간 SSM에 대한 공분산 행렬 은 다음과 같이 지정할 수 있습니다.
Tk=exp{δkA}=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢10⋮0δ1k1!1…δ2k2!δ1k1!…⋱δm−1k(m−1)!δ1k1!1⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥,
δk:=tk+1−tkk<nQ⋆k=Var(η⋆k)Q⋆k=σ2η[δ2m−i−j+1k(m−i)!(m−j)!(2m−i−j+1)]i,j
여기서 인덱스 와 는 과 사이 입니다.ij1m
이제 R로 계산을 수행하려면 KF 전용 패키지와 시변 모델을 수용해야합니다. CRAN 패키지 KFAS 는 좋은 옵션으로 보입니다.
SSM (DT)을 인코딩하기 위해 시간 의 벡터에서 행렬 및 를 계산하는 R 함수를 작성할 수 있습니다
. 패키지가 사용하는 표기법에서, 행렬 는 (DT)의 전이 방정식에서 잡음 를 곱
하게됩니다. 여기서는 그것을 . 또한 여기에서 확산 초기 공분산을 사용해야합니다.TkQ⋆ktkRkη⋆kIm
편집 처음 작성된 잘못이었다. 고정됨 (R 코드 및 이미지에도 동일).Q⋆
CF Ansley and R. Kohn (1986) "스플라인 스무딩에 대한 두 가지 확률 론적 접근 방법의 동등성" J. Appl. 프로 밥. , 23, 391–405 쪽
R. Kohn and CF Ansley (1987) "확률 론적 프로세스 스무딩에 기반한 스플라인 스무딩을위한 새로운 알고리즘" SIAM J. Sci. 및 통계. 계산. , 8 (1), 33–48 쪽
J. Helske (2017). "KFAS : R의 지수 패밀리 상태 공간 모델" J. Stat. 부드러운. , 78 (10), 1-39 페이지
smoothWithDer <- function(t, y, d, m = 3,
Hstar = c(3, 0.2, 0.1)^2, sigma2eta = 1.0^2) {
## define the SSM matrices, depending on 'delta_k' or on 'd_k'
Tfun <- function(delta) {
mat <- matrix(0, nrow = m, ncol = m)
for (i in 0:(m-1)) {
mat[col(mat) == row(mat) + i] <- delta^i / gamma(i + 1)
}
mat
}
Qfun <- function(delta) {
im <- (m - 1):0
x <- delta^im / gamma(im + 1)
mat <- outer(X = x, Y = x, FUN = "*")
im2 <- outer(im, im, FUN = "+")
sigma2eta * mat * delta / (im2 + 1)
}
Zfun <- function(d) {
Z <- matrix(0.0, nrow = 1, ncol = m)
Z[1, d + 1] <- 1.0
Z
}
Hfun <- function(d) ifelse(d >= 0, Hstar[d + 1], 0.0)
Rfun <- function() diag(x = 1.0, nrow = m)
## define arrays by stacking the SSM matrices. We need one more
## 'delta' at the end of the series
n <- length(t)
delta <- diff(t)
delta <- c(delta, mean(delta))
Ta <- Qa <- array(0.0, dim = c(m, m, n))
Za <- array(0.0, dim = c(1, m, n))
Ha <- array(0.0, dim = c(1, 1, n))
Ra <- array(0.0, dim = c(m, m, n))
for (k in 1:n) {
Ta[ , , k] <- Tfun(delta[k])
Qa[ , , k] <- Qfun(delta[k])
Za[ , , k] <- Zfun(d[k])
Ha[ , , k] <- Hfun(d[k])
Ra[ , , k] <- Rfun()
}
require(KFAS)
## define the SSM and perform Kalman Filtering and smoothing
mod <- SSModel(y ~ SSMcustom(Z = Za, T = Ta, R = Ra, Q = Qa, n = n,
P1 = matrix(0, nrow = m, ncol = m),
P1inf = diag(1.0, nrow = m),
state_names = paste0("d", 0:(m-1))) - 1)
out <- KFS(mod, smoothing = "state")
list(t = t, filtered = out$att, smoothed = out$alphahat)
}
## An example function as in OP
f <- function(t, d = rep(0, length = length(t))) {
f <- rep(NA, length(t))
if (any(ind <- (d == 0))) f[ind] <- 2.0 + t[ind] - 0.5 * t[ind]^2
if (any(ind <- (d == 1))) f[ind] <- 1.0 - t[ind]
if (any(ind <- (d == 2))) f[ind] <- -1.0
f
}
set.seed(123)
n <- 100
t <- seq(from = 0, to = 10, length = n)
Hstar <- c(3, 0.4, 0.2)^2
sigma2eta <- 1.0
fTrue <- cbind(d0 = f(t), d1 = f(t, d = 1), d2 = f(t, d = 2))
## ============================================================================
## use a derivative index of -1 to indicate non-observed values, where
## 'y' will be NA
##
## [RUN #0] no derivative m = 2 (cubic spline)
## ============================================================================
d0 <- sample(c(-1, 0), size = n, replace = TRUE, prob = c(0.7, 0.3))
ft0 <- f(t, d0)
## add noise picking the right sd
y0 <- ft0 + rnorm(n = n, sd = c(0.0, sqrt(Hstar))[d0 + 2])
res0 <- smoothWithDer(t, y0, d0, m = 2, Hstar = Hstar)
## ============================================================================
## [RUN #1] Only first order derivative: we can take m = 2 (cubic spline)
## ============================================================================
d1 <- sample(c(-1, 0:1), size = n, replace = TRUE, prob = c(0.7, 0.15, 0.15))
ft1 <- f(t, d1)
y1 <- ft1 + rnorm(n = n, sd = c(0.0, sqrt(Hstar))[d1 + 2])
res1 <- smoothWithDer(t, y1, d1, m = 2, Hstar = Hstar)
## ============================================================================
## [RUN #2] First and second order derivative: we can take m = 3
## (quintic spline)
## ============================================================================
d2 <- sample(c(-1, 0:2), size = n, replace = TRUE, prob = c(0.7, 0.1, 0.1, 0.1))
ft2 <- f(t, d2)
y2 <- ft2 + rnorm(n = n, sd = c(0.0, sqrt(Hstar))[d2 + 2])
res2 <- smoothWithDer(t, y2, d2, m = 3, Hstar = Hstar)
## plots : a ggplot with facets would be better here.
for (run in 0:2) {
resrun <- get(paste0("res", run))
drun <- get(paste0("d", run))
yrun <- get(paste0("y", run))
matplot(t, resrun$smoothed, pch = 16, cex = 0.7, ylab = "", xlab = "")
matlines(t, fTrue, lwd = 2, lty = 1)
for (dv in 0:2) {
points(t[drun == dv], yrun[drun == dv], cex = 1.2, pch = 22, lwd = 2,
bg = "white", col = dv + 1)
}
title(main = sprintf("run %d. Dots = smooothed, lines = true, square = obs", run))
legend("bottomleft", col = 1:3, legend = c("d0", "d1", "d2"), lty = 1)
}
splinefun
미분을 계산할 수 있으며 아마도 역 방법을 사용하여 데이터를 맞추기위한 출발점으로 이것을 사용할 수 있습니까? 이에 대한 해결책을 배우고 싶습니다.