Wir werden beschreiben, wie ein Spline durch Kalman Filtering (KF) -Techniken in Verbindung mit einem State-Space-Modell (SSM) verwendet werden kann. Die Tatsache, dass einige Spline-Modelle von SSM dargestellt und mit KF berechnet werden können, wurde von CF Ansley und R. Kohn in den Jahren 1980-1990 offenbart. Die geschätzte Funktion und ihre Ableitungen sind die von den Beobachtungen abhängigen Erwartungen des Staates. Diese Schätzungen werden unter Verwendung einer festen Intervallglättung berechnet , eine Routineaufgabe bei Verwendung eines SSM.
Der Einfachheit halber sei angenommen, dass die Beobachtungen zu den Zeitpunkten und dass die Beobachtungszahl zu
nur eine Ableitung mit der Ordnung in
. Der Beobachtungsteil des Modells schreibt als
wobei die nicht beobachtete wahre Funktion bezeichnet und
ist ein Gaußscher Fehler mit der Varianz Abhängigkeit von der Ableitungsreihenfolge . Die (zeitkontinuierliche) Übergangsgleichung hat die allgemeine Form
t1<t2<⋯<tnktkdk{0,1,2}y(tk)=f[dk](tk)+ε(tk)(O1)
f(t)ε(tk)H(tk)dkddtα(t)=Aα(t)+η(t)(T1)
wobei der unbeobachtete Zustandsvektor ist und
ein Gaußsches weißes Rauschen mit Kovarianz , von dem angenommen wird, dass es unabhängig von dem ist Beobachtungsrauschen r.vs . Um einen Spline zu beschreiben, betrachten wir einen Zustand, der durch Stapeln der
ersten Ableitungen erhalten wird, dh . Der Übergang ist
α(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 )
und wir erhalten dann einen Polynom-Spline mit der Größenordnung (und Grad
). Während dem üblichen kubischen Spline entspricht,2m2m−1m=2>1. Um an einem klassischen SSM-Formalismus festzuhalten, können wir (O1) umschreiben als
wobei die Beobachtungsmatrix die geeignete Ableitung in und die Varianz von
in Abhängigkeit von . Also wobei ,
und . In ähnlicher Weise isty(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 ≤ 3für drei Varianzen ,
und . H⋆1H⋆2H⋆3
Obwohl der Übergang in kontinuierlicher Zeit erfolgt, handelt es sich bei der KF tatsächlich um eine diskrete Standardzeit . Tatsächlich werden wir in der Praxis konzentrieren sich auf Zeiten , wo wir eine Beobachtung haben, oder wo wollen wir die Derivate schätzen. Wir können die Menge als die Vereinigung dieser beiden Mengen von Zeiten annehmen und annehmen, dass die Beobachtung zu fehlen kann: Dies erlaubt es, die Ableitungen zu jedem Zeitpunkt
unabhängig von der Existenz einer Beobachtung abzuschätzen . Es bleibt noch die diskrete SSM abzuleiten.t{ tk}tkmtk
Wir verwenden Indizes für diskrete Zeiten und schreiben für
und so weiter. Die zeitdiskrete SSM hat die Form
wo die Matrizen und werden von (T1) und (O2) abgeleitet, während die Varianz von durch
vorausgesetzt, dassαkα ( tk)αk+1yk=Tkαk+η⋆k=Zkαk+εk(DT)
TkQ.⋆k: = Var ( η⋆k)εkHk= H⋆dk+ 1ykTk=exp{δkA}=[ 1 δ 1 kfehlt nicht. Mit etwas Algebra können wir die Übergangsmatrix für die zeitdiskrete SSM finden.
wobei für . Ebenso kann die Kovarianzmatrix für die zeitdiskrete SSM als angegeben werden
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
wobei die Indizes und zwischen und .ij1m
Um nun die Berechnung in R fortzusetzen, benötigen wir ein Paket, das sich mit KF befasst und zeitvariable Modelle akzeptiert. Das CRAN-Paket KFAS scheint eine gute Option zu sein. Wir können R-Funktionen schreiben, um die Matrizen und aus dem Vektor der Zeiten zu berechnen
, um die SSM (DT) zu codieren. In den vom Paket verwendeten Notationen multipliziert eine Matrix das Rauschen
in der Übergangsgleichung von (DT): Wir nehmen hier die Identität . Beachten Sie auch, dass hier eine diffuse initiale Kovarianz verwendet werden muss.TkQ⋆ktkRkη⋆kIm
EDIT Der ursprünglich geschriebene war falsch. Behoben (auch in R-Code und Bild).Q⋆
CF Ansley und R. Kohn (1986) "Zur Äquivalenz zweier stochastischer Ansätze zur Spline-Glättung" J. Appl. Probab. 23, S. 391–405
R. Kohn und CF Ansley (1987) "Ein neuer Algorithmus zur Spline-Glättung basierend auf der Glättung eines stochastischen Prozesses" SIAM J. Sci. und Stat. Comput. 8 (1), S. 33–48
J. Helske (2017). KFAS: Modelle des exponentiellen Familienzustandsraums in R J. Stat. Sanft. 78 (10), S. 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
kann aber Ableitungen berechnen, und vermutlich können Sie diese als Ausgangspunkt verwenden, um die Daten mit einigen inversen Methoden anzupassen? Ich bin daran interessiert, die Lösung dafür zu erfahren.