Nous décrirons comment une spline peut être utilisée par des techniques de filtrage de Kalman (KF) en relation avec un modèle d'état-espace (SSM). Le fait que certains modèles de splines puissent être représentés par SSM et calculés avec KF a été révélé par CF Ansley et R. Kohn dans les années 1980-1990. La fonction estimée et ses dérivées sont les attentes de l'état conditionnées par les observations. Ces estimations sont calculées en utilisant un lissage à intervalle fixe , une tâche de routine lors de l'utilisation d'un SSM.
Par souci de simplicité, supposons que les observations soient faites aux instants et que le nombre d'observation à
n'implique qu'une seule dérivée d'ordre dans
. La partie observation du modèle s'écrit comme
où dénote la fonction vraie non observée et
est une erreur gaussienne de variance fonction de l'ordre de dérivation . L'équation de transition (temps continu) prend la forme générale
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)
α(t)η(t)Qε(tk)mα(t):=[f(t),
où est le vecteur d'état non observé et
est un bruit blanc gaussien de covariance , supposé indépendant du bruit d'observation r.vs . Pour décrire une spline, nous considérons un état obtenu en empilant les
premières dérivées, à savoir . La transition est
α(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 )
et on obtient alors une spline polynomiale d'ordre (et degré
). Alors que correspond à la spline cubique habituelle,2m2m−1m=2>1. Afin de nous en tenir au formalisme SSM classique, nous pouvons réécrire (O1) sous la forme
où la matrice d'observation sélectionne la dérivée appropriée dans et la variance de
est choisie en fonction de . Donc où ,
et . De mêmey(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 ⋆ 3pour trois variances ,
et . H⋆1H⋆2H⋆3
Bien que la transition soit en temps continu, le KF est en fait un temps discret standard . En effet, nous nous concentrerons en pratique sur les moments où nous avons une observation, ou où nous voulons estimer les dérivées. On peut prendre l'ensemble comme l'union de ces deux ensembles de temps et supposer que l'observation à peut être manquante: cela permet d'estimer les dérivées à tout instant
quelle que soit l'existence d'une observation. Il reste à dériver le SSM discret.t{tk}tkmtk
Nous utiliserons des indices pour les temps discrets, en écrivant pour
et ainsi de suite. Le SSM à temps discret prend la forme
où les matrices et sont dérivés de (T1) et (O2) tandis que la variance de est donnée par
condition queαkα(tk)αk+1yk=Tkαk+η⋆k=Zkαk+εk(DT)
TkQ⋆k:=Var(η⋆k)εkHk=H⋆dk+1ykTk=exp{δkA}=[ 1 δ 1 kne manque pas. En utilisant une algèbre, nous pouvons trouver la matrice de transition pour le SSM à temps discret
où pour . De même, la matrice de covariance pour le SSM à temps discret peut être donnée comme
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
où les indices et sont compris entre et .ij1m
Maintenant, pour reporter le calcul dans R, nous avons besoin d'un package dédié à KF et acceptant des modèles variant dans le temps; le package CRAN KFAS semble une bonne option. Nous pouvons écrire des fonctions R pour calculer les matrices
et partir du vecteur de temps
afin de coder le SSM (DT). Dans les notations utilisées par le package, une matrice vient multiplier le bruit
dans l'équation de transition de (DT): on la prend ici pour être l'identité . Notez également qu'une covariance initiale diffuse doit être utilisée ici.TkQ⋆ktkRkη⋆kIm
EDIT L' telle qu'écrite initialement était incorrecte. Fixe (également dans le code R et l'image).Q⋆
CF Ansley et R. Kohn (1986) "Sur l'équivalence de deux approches stochastiques du lissage des splines" J. Appl. Probab. , 23, pp. 391–405
R. Kohn et CF Ansley (1987) "Un nouvel algorithme pour le lissage de spline basé sur le lissage d'un processus stochastique" SIAM J. Sci. et Stat. Comput. , 8 (1), pp. 33–48
J.Helske (2017). "KFAS: Modèles d'espace d'états familiaux exponentiels dans R" J. Stat. Doux. , 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
pouvez-vous calculer des dérivées et vous pourriez probablement l'utiliser comme point de départ pour ajuster les données en utilisant des méthodes inverses? Je suis intéressé d'apprendre la solution à cela.