Describiremos cómo se puede usar una spline a través de las técnicas de filtrado de Kalman (KF) en relación con un modelo de espacio de estado (SSM). El hecho de que algunos modelos spline puedan ser representados por SSM y calculados con KF fue revelado por CF Ansley y R. Kohn en los años 1980-1990. La función estimada y sus derivados son las expectativas del estado condicionadas a las observaciones. Estas estimaciones se calculan utilizando un suavizado de intervalo fijo , una tarea de rutina cuando se utiliza un SSM.
En aras de la simplicidad, suponga que las observaciones se realizan en los momentos t1<t2<⋯<tn y que el número de observación k en
tk involucra solo una derivada con el orden dk en
{0,1,2} . La parte de observación del modelo se escribe como
y(tk)=f[dk](tk)+ε(tk)(O1)
dondef(t) denota lafunciónverdaderano observadayε(tk)
es un error gaussiano con varianzaH(tk) dependiendo del orden de derivacióndk. La ecuación de transición (tiempo continuo) toma la forma general
donde es el vector de estado no observado y
es un ruido blanco gaussiano con covarianza , se supone que es independiente del ruido de observación r.vs . Para describir una spline, consideramos un estado obtenido al apilar las
primeras derivadas, es decir, . La transición es
ddtα(t)=Aα(t)+η(t)(T1)
α(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 )
y luego obtenemos una spline polinomial con orden (y grado
). Mientras que corresponde a la spline cúbica habitual,2m2m−1m=2>1. Para mantener un formalismo SSM clásico, podemos reescribir (O1) como
donde la matriz de observación selecciona la derivada adecuada en y la varianza de
se elige dependiendo de . Entonces donde ,
y . Del mismo modoy(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 ⋆ 3para tres variaciones ,
y . H⋆1H⋆2H⋆3
Aunque la transición es en tiempo continuo, el KF es en realidad un tiempo discreto estándar . De hecho, en la práctica nos centraremos en los tiempos donde tenemos una observación, o donde queremos estimar las derivadas. Podemos tomar el conjunto como la unión de estos dos conjuntos de tiempos y asumir que puede faltar la observación en : esto permite estimar las derivadas en cualquier momento
independientemente de la existencia de una observación. Queda por derivar el SSM discreto.t{tk}tkmtk
Usaremos índices para tiempos discretos, escribiendo para
y así sucesivamente. El SSM de tiempo discreto toma la forma
donde las matrices y se derivan de (T1) y (O2) mientras que la varianza de viene dada por
siempre queαkα(tk)αk+1yk=Tkαk+η⋆k=Zkαk+εk(DT)
TkQ⋆k:=Var(η⋆k)εkHk=H⋆dk+1ykTk=exp{δkA}=[ 1 δ 1 kNo falta. Usando algo de álgebra podemos encontrar la matriz de transición para el SSM de tiempo discreto
where para . De manera similar, la matriz de covarianza para el SSM de tiempo discreto se puede dar como
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
donde los índices y están entre y .ij1m
Ahora, para transferir el cálculo en R, necesitamos un paquete dedicado a KF y que acepte modelos que varían con el tiempo; El paquete CRAN KFAS parece una buena opción. Podemos escribir funciones R para calcular las matrices
y partir del vector de tiempos
para codificar el SSM (DT). En las anotaciones utilizadas por el paquete, una matriz viene a multiplicar el ruido
en la ecuación de transición de (DT): lo consideramos aquí como la identidad . También tenga en cuenta que aquí debe usarse una covarianza inicial difusa.TkQ⋆ktkRkη⋆kIm
EDITAR La como se escribió inicialmente era incorrecta. Corregido (también en código R e imagen).Q⋆
CF Ansley y R. Kohn (1986) "Sobre la equivalencia de dos enfoques estocásticos para el suavizado de estrías" J. Appl. Probab , 23, págs. 391–405
R. Kohn y CF Ansley (1987) "Un nuevo algoritmo para el suavizado de estrías basado en el suavizado de un proceso estocástico" SIAM J. Sci. y Stat. Comput , 8 (1), págs. 33–48
J. Helske (2017). "KFAS: Modelos de espacio de estado familiar exponencial en R" J. Stat. Suave. , 78 (10), pp. 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
puedo calcular derivados y presumiblemente podría usar esto como punto de partida para ajustar los datos utilizando algunos métodos inversos? Estoy interesado en aprender la solución a esto.