#+OPTIONS: H:3 num:nil toc:nil \n:nil @:t ::t |:t ^:nil -:t f:t *:t TeX:t LaTeX:t skip:t d:t tags:not-in-toc creator:t timestamp:nil author:nil title:nil html5-fancy:t #+HTML_DOCTYPE: html5 #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+HTML_HEAD: #+LANGUAGE: fr #+STARTUP: latexpreview #+TITLE: Le filtre de Kalman et le filtre de Hodrick-Prescott #+DATE: Septembre 2026 #+AUTHOR: Stéphane Adjemian #+EMAIL: stephane.adjemian@univ-lemans.fr #+PROPERTY: header-args:python :python /tmp/blog-kalman/bin/python #+BEGIN_QUOTE Le filtre de Kalman calcule récursivement la loi d'un vecteur d'état non observé sachant les observations passées, dans un modèle linéaire et gaussien écrit sous forme état-mesure. Cette note dérive en détail le filtre, le lisseur, qui exploite aussi les observations futures, et la vraisemblance, qui s'obtient comme un sous-produit du filtre. Elle étudie la convergence du filtre vers un régime permanent et, pour le modèle de niveau local, son lien avec le lissage exponentiel. L'application montre que le filtre de Hodrick-Prescott est le lisseur d'un modèle de tendance particulier, ce qui permet d'estimer par le maximum de vraisemblance le paramètre de lissage que l'on fixe d'ordinaire a priori. Les calculs portent sur le PIB par tête français depuis 1820 et sont faits en Python, avec une implémentation du filtre en une trentaine de lignes. Les corrigés des exercices sont donnés dans des blocs dépliables. #+END_QUOTE \\ \\ \\ #+BEGIN_SRC bash :results silent :exports none :async t python3 -m venv /tmp/blog-kalman source /tmp/blog-kalman/bin/activate pip install numpy scipy matplotlib pandas openpyxl statsmodels #+END_SRC #+begin_src python :session kalman :exports none :results none import os import urllib.request as url import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy import sparse from scipy.sparse.linalg import spsolve from scipy.linalg import solve_discrete_lyapunov, solve_discrete_are from scipy.optimize import minimize, minimize_scalar from scipy.stats import chi2 rng = np.random.default_rng(2014) def virgule(x): return f'{x}'.replace('.', '{,}') #+end_src * Modèles état-mesure :PROPERTIES: :CUSTOM_ID: modele-etat-mesure :END: Un modèle état-mesure distingue ce que l'on observe, une série $y_t$, de la dynamique non observée qui l'engendre, résumée par un vecteur d'état $\alpha_t$. Le cadre est très général\nbsp{}: les processus ARMA, les modèles à composantes inobservées (tendance, cycle, saisonnalité), les régressions à coefficients variables ou les modèles DSGE linéarisés s'y écrivent tous. On reprend la notation de Harvey (/Forecasting, Structural Time Series Models and the Kalman Filter/, 1989) et de Durbin et Koopman (/Time Series Analysis by State Space Methods/, 2012), à une différence de datation près dans l'équation d'état. #+BEGIN_definition Un modèle état-mesure est défini par une équation de mesure et une équation d'état\nbsp{}: \begin{equation*} \begin{aligned} y_t &= Z_t\alpha_t + d_t + \varepsilon_t, &\qquad \varepsilon_t &\sim \mathcal N(0, H_t),\\ \alpha_t &= T_t\alpha_{t-1} + c_t + R_t\eta_t, &\qquad \eta_t &\sim \mathcal N(0, Q_t), \end{aligned} \end{equation*} pour $t = 1, \dots, n$, avec la condition initiale \(\alpha_0 \sim \mathcal N(a_0, P_0)\). L'observation $y_t$ appartient à $\mathbb R^p$, l'état $\alpha_t$ à $\mathbb R^m$ et la perturbation d'état $\eta_t$ à $\mathbb R^r$. Les matrices $Z_t$ de taille $p\times m$, $T_t$ de taille $m\times m$, $R_t$ de taille $m\times r$, $H_t$ de taille $p\times p$ et $Q_t$ de taille $r\times r$, ainsi que les vecteurs $d_t$ et $c_t$, sont non aléatoires. Les variables $\alpha_0$, $\varepsilon_1, \dots, \varepsilon_n$ et $\eta_1, \dots, \eta_n$ sont mutuellement indépendantes. #+END_definition On note $Y_t = \{y_1, \dots, y_t\}$ l'information disponible à la date $t$, avec $Y_0 = \emptyset$, et $n$ la taille de l'échantillon, la lettre $T$ étant réservée à la matrice de transition. Le vecteur d'état résume tout le passé\nbsp{}: la suite des états est une chaîne de Markov et, sachant les états, les observations sont indépendantes, $y_t$ ne dépendant que de $\alpha_t$. La matrice de sélection $R_t$ permet d'avoir moins de chocs que d'états, ce qui est la règle dès que l'état contient des valeurs retardées. ** Exemples :PROPERTIES: :CUSTOM_ID: exemples :END: #+BEGIN_exemple Le modèle de niveau local est une marche aléatoire observée avec un bruit\nbsp{}: \begin{equation*} y_t = \mu_t + \varepsilon_t,\qquad \mu_t = \mu_{t-1} + \eta_t, \end{equation*} avec $\varepsilon_t \sim \mathcal N(0, \sigma_\varepsilon^2)$ et $\eta_t \sim \mathcal N(0, \sigma_\eta^2)$. L'état est le niveau, $\alpha_t = \mu_t$, et les matrices du système sont des scalaires\nbsp{}: \(Z = T = R = 1\), \(H = \sigma_\varepsilon^2\), \(Q = \sigma_\eta^2\) et $d = c = 0$. #+END_exemple #+BEGIN_exemple Le modèle de tendance linéaire locale ajoute une pente stochastique $\beta_t$ au niveau\nbsp{}: \begin{equation*} y_t = \mu_t + \varepsilon_t,\qquad \mu_t = \mu_{t-1} + \beta_{t-1} + \eta_t,\qquad \beta_t = \beta_{t-1} + \zeta_t, \end{equation*} où les trois perturbations sont des bruits blancs gaussiens indépendants, de variances $\sigma_\varepsilon^2$, $\sigma_\eta^2$ et $\sigma_\zeta^2$. L'état est $\alpha_t = (\mu_t, \beta_t)'$ et \begin{equation*} Z = \begin{pmatrix} 1 & 0 \end{pmatrix},\quad T = \begin{pmatrix} 1 & 1\\ 0 & 1 \end{pmatrix},\quad R = I_2,\quad H = \sigma_\varepsilon^2,\quad Q = \begin{pmatrix} \sigma_\eta^2 & 0\\ 0 & \sigma_\zeta^2 \end{pmatrix}. \end{equation*} Le cas particulier $\sigma_\eta^2 = 0$ est le /modèle de tendance lisse/\nbsp{}: le niveau n'est plus perturbé directement, seule la pente l'est, et la tendance est une courbe régulière. Seule la seconde colonne de $R$ subsiste, \(R = (0, 1)'\), et \(Q = \sigma_\zeta^2\). Ce modèle joue le premier rôle dans l'application. #+END_exemple #+BEGIN_exemple Un processus autorégressif d'ordre $p$, \(y_t = \phi_1 y_{t-1} + \dots + \phi_p y_{t-p} + \eta_t\), s'écrit sous forme état-mesure en empilant les valeurs retardées dans l'état, \(\alpha_t = (y_t, y_{t-1}, \dots, y_{t-p+1})'\)\nbsp{}: \begin{equation*} Z = \begin{pmatrix} 1 & 0 & \cdots & 0 \end{pmatrix},\quad T = \begin{pmatrix} \phi_1 & \phi_2 & \cdots & \phi_{p-1} & \phi_p\\ 1 & 0 & \cdots & 0 & 0\\ 0 & 1 & \cdots & 0 & 0\\ \vdots & & \ddots & & \vdots\\ 0 & 0 & \cdots & 1 & 0 \end{pmatrix},\quad R = \begin{pmatrix} 1\\ 0\\ \vdots\\ 0 \end{pmatrix}, \end{equation*} avec $H = 0$ et $Q = \sigma^2$. L'observation est parfaite, sans erreur de mesure\nbsp{}: toute l'incertitude porte sur l'état. #+END_exemple #+BEGIN_exemple Pour un processus ARMA($p$, $q$), \(y_t = \sum_{i=1}^p \phi_i y_{t-i} + \eta_t + \sum_{j=1}^q \theta_j\eta_{t-j}\), Harvey (1989) pose $s = \max(p, q+1)$, complète les coefficients par des zéros, $\phi_i = 0$ pour $i > p$ et $\theta_j = 0$ pour $j > q$, et prend un état de dimension $s$ avec \begin{equation*} Z = \begin{pmatrix} 1 & 0 & \cdots & 0 \end{pmatrix},\quad T = \begin{pmatrix} \phi_1 & 1 & 0 & \cdots & 0\\ \phi_2 & 0 & 1 & \cdots & 0\\ \vdots & & & \ddots & \\ \phi_{s-1} & 0 & 0 & \cdots & 1\\ \phi_s & 0 & 0 & \cdots & 0 \end{pmatrix},\quad R = \begin{pmatrix} 1\\ \theta_1\\ \vdots\\ \theta_{s-1} \end{pmatrix}, \end{equation*} $H = 0$ et $Q = \sigma^2$. Pour un ARMA(1,1), l'état \(\alpha_t = (\alpha_{1,t}, \alpha_{2,t})'\) vérifie \(\alpha_{2,t} = \theta\eta_t\) et \begin{equation*} \alpha_{1,t} = \phi\alpha_{1,t-1} + \alpha_{2,t-1} + \eta_t = \phi\alpha_{1,t-1} + \eta_t + \theta\eta_{t-1}, \end{equation*} et comme $y_t = \alpha_{1,t}$, on retrouve bien le processus ARMA(1,1). Le cas $p = 0$ donne la représentation d'un processus MA($q$). #+END_exemple #+BEGIN_remarque La représentation état-mesure d'un processus n'est pas unique. Pour toute matrice inversible $M$ de taille $m\times m$, l'état \(\alpha_t^* = M\alpha_t\) définit un modèle aux mêmes observations, dont les matrices sont \begin{equation*} \begin{gathered} Z^* = ZM^{-1},\quad T^* = MTM^{-1},\quad R^* = MR,\\ c^* = Mc,\quad a_0^* = Ma_0,\quad P_0^* = MP_0M'. \end{gathered} \end{equation*} Le filtre donne \(a_{t|t}^* = Ma_{t|t}\) et \(P_{t|t}^* = MP_{t|t}M'\), mais les innovations, leurs variances, la vraisemblance et les prévisions de $y_t$ sont inchangées. Pour le processus MA(1) \(y_t = \eta_t + \theta\eta_{t-1}\), la forme de Harvey ci-dessus, d'état $(y_t, \theta\eta_t)'$, et celle de Hamilton (/Time Series Analysis/, 1994), d'état $(\eta_t, \eta_{t-1})'$, avec \(Z = \begin{pmatrix} 1 & \theta \end{pmatrix}\), \(T = \begin{pmatrix} 0 & 0\\ 1 & 0 \end{pmatrix}\) et $R = (1, 0)'$, se déduisent l'une de l'autre par \begin{equation*} M = \begin{pmatrix} 1 & \theta\\ \theta & 0 \end{pmatrix}, \end{equation*} inversible dès que $\theta \neq 0$. On peut aussi augmenter la dimension de l'état par des composantes que les chocs n'atteignent pas ou que les observations ne voient pas. Une représentation est minimale lorsqu'elle est commandable et observable, et deux représentations minimales de la même relation entre les chocs et les observations se déduisent l'une de l'autre par un changement de base (Hannan et Deistler, /The Statistical Theory of Linear Systems/, 1988, chapitre 2). Enfin, des structures de chocs différentes peuvent engendrer la même loi des observations\nbsp{}: le modèle de niveau local, à deux chocs indépendants, a la loi d'un processus ARIMA(0,1,1) à un seul choc, comme on le verra dans la section sur la [[#forme-reduite][forme réduite]]. Le choix de la représentation est donc affaire de commodité pour le filtrage et la vraisemblance. En revanche, les paramètres d'une représentation dont toutes les matrices seraient libres ne seraient pas identifiés\nbsp{}: les modèles structurels lèvent cette indétermination en fixant $Z$, $T$ et $R$. #+END_remarque Une composante saisonnière stochastique, un cycle ou des variables explicatives s'ajoutent de la même façon, en augmentant le vecteur d'état\nbsp{}: c'est ce qui fait l'intérêt pratique du cadre. Dans la suite, les matrices du système sont constantes et il n'y a pas de termes déterministes ($d = c = 0$). Le code du filtre traite des observations vectorielles, mais les fonctions de vraisemblance et les applications supposent une observation scalaire ($p = 1$). Un modèle est représenté par une fonction qui renvoie ses cinq matrices\nbsp{}: #+begin_src python :session kalman :exports code :results none def niveau_local(s2_eps, s2_eta): Z, T, R = np.eye(1), np.eye(1), np.eye(1) return Z, T, R, np.array([[s2_eps]]), np.array([[s2_eta]]) def tendance_lineaire_locale(s2_eps, s2_eta, s2_zeta): Z = np.array([[1.0, 0.0]]) T = np.array([[1.0, 1.0], [0.0, 1.0]]) R = np.eye(2) return Z, T, R, np.array([[s2_eps]]), np.diag([s2_eta, s2_zeta]) def tendance_lisse(s2_eps, s2_zeta): Z, T, _, H, _ = tendance_lineaire_locale(s2_eps, 0.0, s2_zeta) R = np.array([[0.0], [1.0]]) return Z, T, R, H, np.array([[s2_zeta]]) #+end_src * Le filtre de Kalman :PROPERTIES: :CUSTOM_ID: filtre :END: ** Objectif :PROPERTIES: :CUSTOM_ID: objectif :END: On cherche la loi de l'état $\alpha_t$ sachant une information $Y_s$. On note \begin{equation*} a_{t|s} = \mathbb E\left[\alpha_t \mid Y_s\right],\qquad P_{t|s} = \mathbb V\left[\alpha_t \mid Y_s\right] \end{equation*} son espérance et sa matrice de variance conditionnelles. Trois cas se présentent\nbsp{}: la /prédiction/ si $s = t-1$, le /filtrage/ si $s = t$ et le /lissage/ si $s = n$. Le filtre de Kalman calcule $a_{t|t-1}$, $P_{t|t-1}$, $a_{t|t}$ et $P_{t|t}$ pour $t = 1, \dots, n$, récursivement, en intégrant une observation à chaque étape. Dans un modèle gaussien, la loi conditionnelle de l'état est normale, donc entièrement décrite par ces deux moments, et l'espérance conditionnelle est le meilleur prédicteur de $\alpha_t$ au sens de l'erreur quadratique moyenne, parmi toutes les fonctions des observations. #+BEGIN_remarque Sans l'hypothèse de normalité, mais avec des perturbations non corrélées entre elles et d'une date à l'autre, les récurrences établies plus bas restent valides si l'on remplace l'espérance conditionnelle par la projection linéaire\nbsp{}: $a_{t|t}$ est alors le meilleur prédicteur /linéaire/ de $\alpha_t$ en fonction de $y_1, \dots, y_t$, et $P_{t|t}$ la matrice de variance de son erreur (Harvey, 1989, chapitre 3). #+END_remarque ** Un lemme sur la loi normale :PROPERTIES: :CUSTOM_ID: lemme-gaussien :END: Toute la dérivation repose sur un résultat élémentaire, la loi conditionnelle d'un vecteur gaussien. #+BEGIN_lemma Soit un vecteur gaussien \begin{equation*} \begin{pmatrix} x\\ y \end{pmatrix} \sim \mathcal N\left(\begin{pmatrix} \mu_x\\ \mu_y \end{pmatrix}, \begin{pmatrix} \Sigma_{xx} & \Sigma_{xy}\\ \Sigma_{yx} & \Sigma_{yy} \end{pmatrix}\right) \end{equation*} où $\Sigma_{yy}$ est inversible. La loi de $x$ sachant $y$ est normale\nbsp{}: \begin{equation*} x \mid y \sim \mathcal N\left(\mu_x + \Sigma_{xy}\Sigma_{yy}^{-1}(y - \mu_y),\; \Sigma_{xx} - \Sigma_{xy}\Sigma_{yy}^{-1}\Sigma_{yx}\right). \end{equation*} #+END_lemma #+BEGIN_proof Posons \(e = x - \mu_x - \Sigma_{xy}\Sigma_{yy}^{-1}(y - \mu_y)\). Le vecteur $(e, y)$ est une transformation affine de $(x, y)$, il est donc gaussien. La covariance entre $e$ et $y$ est nulle\nbsp{}: \begin{equation*} \mathrm{Cov}(e, y) = \Sigma_{xy} - \Sigma_{xy}\Sigma_{yy}^{-1}\Sigma_{yy} = 0. \end{equation*} Pour un vecteur gaussien, l'absence de corrélation équivaut à l'indépendance\nbsp{}: $e$ est indépendant de $y$. Dans la décomposition \begin{equation*} x = \mu_x + \Sigma_{xy}\Sigma_{yy}^{-1}(y - \mu_y) + e, \end{equation*} le premier terme est une fonction de $y$ et le second est indépendant de $y$. Sachant $y$, le vecteur $x$ est donc la somme d'une constante et d'un vecteur gaussien de loi $\mathcal N(0, \mathbb V[e])$, ce qui établit la normalité de la loi conditionnelle et donne son espérance. Sa variance est \begin{equation*} \mathbb V[e] = \mathrm{Cov}(e, x) = \Sigma_{xx} - \Sigma_{xy}\Sigma_{yy}^{-1}\Sigma_{yx}, \end{equation*} la première égalité venant de ce que $e$ diffère de $x$ par une fonction affine de $y$, avec laquelle $e$ n'est pas corrélé. #+END_proof ** Les équations du filtre :PROPERTIES: :CUSTOM_ID: equations-filtre :END: #+BEGIN_proposition Partant de $a_{0|0} = a_0$ et $P_{0|0} = P_0$, les moments conditionnels de l'état se calculent pour $t = 1, \dots, n$ par une étape de /prédiction/, \begin{equation*} \begin{aligned} a_{t|t-1} &= T_t a_{t-1|t-1} + c_t,\\ P_{t|t-1} &= T_t P_{t-1|t-1} T_t' + R_t Q_t R_t', \end{aligned} \end{equation*} suivie d'une étape de /mise à jour/, \begin{equation*} \begin{aligned} v_t &= y_t - Z_t a_{t|t-1} - d_t, & F_t &= Z_t P_{t|t-1} Z_t' + H_t,\\ K_t &= P_{t|t-1} Z_t' F_t^{-1}, & &\\ a_{t|t} &= a_{t|t-1} + K_t v_t, & P_{t|t} &= (I_m - K_t Z_t) P_{t|t-1}. \end{aligned} \end{equation*} La loi de $\alpha_t$ sachant $Y_t$ est normale, d'espérance $a_{t|t}$ et de variance $P_{t|t}$. Le vecteur $v_t$ est l'/innovation/, $F_t$ sa matrice de variance et $K_t$ le /gain/ du filtre. #+END_proposition #+BEGIN_proof On raisonne par récurrence. Supposons que la loi de $\alpha_{t-1}$ sachant $Y_{t-1}$ soit $\mathcal N(a_{t-1|t-1}, P_{t-1|t-1})$, ce qui est vrai pour $t = 1$ puisque $Y_0$ est vide. /Prédiction./ Les observations $y_1, \dots, y_{t-1}$ sont des fonctions de $\alpha_0$ et des perturbations $\varepsilon_s$ et $\eta_s$ pour \(s \leq t-1\)\nbsp{}: comme $\alpha_{t-1}$, elles sont indépendantes de $\eta_t$. Sachant $Y_{t-1}$, l'état \(\alpha_t = T_t\alpha_{t-1} + c_t + R_t\eta_t\) est donc une transformation affine de deux vecteurs gaussiens indépendants. Sa loi est normale, d'espérance $T_t a_{t-1|t-1} + c_t$ et de variance $T_t P_{t-1|t-1} T_t' + R_t Q_t R_t'$. /Loi jointe de l'état et de l'observation./ La perturbation $\varepsilon_t$ est indépendante de $\alpha_t$ et de $Y_{t-1}$. Sachant $Y_{t-1}$, le couple formé par $\alpha_t$ et \(y_t = Z_t\alpha_t + d_t + \varepsilon_t\) est donc gaussien\nbsp{}: \begin{equation*} \begin{pmatrix} \alpha_t\\ y_t \end{pmatrix} \Bigm| Y_{t-1} \sim \mathcal N\left(\begin{pmatrix} a_{t|t-1}\\ Z_t a_{t|t-1} + d_t \end{pmatrix}, \begin{pmatrix} P_{t|t-1} & P_{t|t-1} Z_t'\\ Z_t P_{t|t-1} & F_t \end{pmatrix}\right), \end{equation*} la covariance conditionnelle venant de \(\mathrm{Cov}(\alpha_t, Z_t\alpha_t + \varepsilon_t \mid Y_{t-1}) = P_{t|t-1}Z_t'\). /Mise à jour./ Conditionner par $Y_t$, c'est conditionner par $Y_{t-1}$ puis par $y_t$. On applique donc le lemme à la loi jointe précédente, avec $x = \alpha_t$ et $y = y_t$. La loi de $\alpha_t$ sachant $Y_t$ est normale, d'espérance \begin{equation*} a_{t|t-1} + P_{t|t-1}Z_t'F_t^{-1}\left(y_t - Z_t a_{t|t-1} - d_t\right) = a_{t|t-1} + K_t v_t \end{equation*} et de variance \(P_{t|t-1} - P_{t|t-1}Z_t'F_t^{-1}Z_t P_{t|t-1} = (I_m - K_t Z_t)P_{t|t-1}\), ce qui achève la récurrence. #+END_proof #+BEGIN_remarque Le gain dose la correction apportée par l'observation. Dans le cas scalaire, \(K_t = P_{t|t-1}Z_t/(Z_t^2P_{t|t-1} + H_t)\). Si la mesure est parfaite ($H_t = 0$), le gain vaut $1/Z_t$ et l'état filtré se déduit exactement de l'observation. Si la mesure est très bruitée ($H_t \to \infty$), ou si l'état est déjà connu avec précision ($P_{t|t-1} \to 0$), le gain tend vers zéro et l'observation est ignorée. On remarque aussi que les variances $P_{t|t-1}$, $F_t$ et $P_{t|t}$ ne dépendent pas des observations\nbsp{}: on pourrait les calculer avant même de disposer des données. #+END_remarque #+BEGIN_property La variance filtrée s'écrit aussi sous la /forme de Joseph/\nbsp{}: \begin{equation*} P_{t|t} = (I_m - K_t Z_t) P_{t|t-1} (I_m - K_t Z_t)' + K_t H_t K_t'. \end{equation*} #+END_property #+BEGIN_proof En développant le membre de droite, on obtient \begin{equation*} P_{t|t-1} - K_t Z_t P_{t|t-1} - P_{t|t-1} Z_t' K_t' + K_t (Z_t P_{t|t-1} Z_t' + H_t) K_t'. \end{equation*} Le dernier terme vaut \(K_t F_t K_t' = P_{t|t-1}Z_t'K_t'\), puisque \(K_t F_t = P_{t|t-1}Z_t'\). Il compense le troisième, et il reste $(I_m - K_tZ_t)P_{t|t-1}$. #+END_proof Les deux expressions de $P_{t|t}$ sont égales en arithmétique exacte, mais pas en arithmétique flottante. La forme de Joseph est une somme de deux matrices symétriques semi-définies positives\nbsp{}: elle le reste quelles que soient les erreurs d'arrondi sur le gain, alors que la forme courte retranche deux termes presque égaux lorsque $P_{t|t-1}$ est grand et peut produire une matrice non symétrique, voire des variances négatives. On verra que ce cas se présente à l'initialisation. L'implémentation suit les équations à la lettre, avec la forme de Joseph. Une observation manquante, codée =np.nan=, est traitée en sautant l'étape de mise à jour\nbsp{}: sans observation, la loi filtrée est la loi prédite. #+begin_src python :session kalman :exports code :results none def filtre_kalman(y, Z, T, R, H, Q, a0, P0): y = np.asarray(y, dtype=float).reshape(len(y), -1) n, p = y.shape m = len(a0) RQR = R @ Q @ R.T res = {'a_pred': np.zeros((n, m)), 'P_pred': np.zeros((n, m, m)), 'a_filt': np.zeros((n, m)), 'P_filt': np.zeros((n, m, m)), 'v': np.full((n, p), np.nan), 'F': np.full((n, p, p), np.nan), 'K': np.zeros((n, m, p))} a, P = np.asarray(a0, dtype=float), np.asarray(P0, dtype=float) for t in range(n): # Prédiction a = T @ a P = T @ P @ T.T + RQR res['a_pred'][t], res['P_pred'][t] = a, P # Mise à jour, sautée si l'observation est manquante if not np.isnan(y[t]).any(): v = y[t] - Z @ a F = Z @ P @ Z.T + H K = np.linalg.solve(F, Z @ P).T # P Z' F^{-1} a = a + K @ v IKZ = np.eye(m) - K @ Z P = IKZ @ P @ IKZ.T + K @ H @ K.T # forme de Joseph res['v'][t], res['F'][t], res['K'][t] = v, F, K res['a_filt'][t], res['P_filt'][t] = a, P return res #+end_src La fonction renvoie un dictionnaire de tableaux indexés par la date, de $0$ à $n-1$ en Python pour les dates $1$ à $n$ de la note. ** Les innovations :PROPERTIES: :CUSTOM_ID: innovations :END: #+BEGIN_property L'innovation $v_t$ est indépendante de $Y_{t-1}$ et suit la loi $\mathcal N(0, F_t)$. Les innovations $v_1, \dots, v_n$ sont indépendantes\nbsp{}: elles forment un bruit blanc gaussien, hétéroscédastique si $F_t$ varie avec $t$. #+END_property #+BEGIN_proof D'après la loi jointe établie dans la preuve du filtre, la loi de $y_t$ sachant $Y_{t-1}$ est $\mathcal N(Z_t a_{t|t-1} + d_t, F_t)$, donc celle de $v_t$ sachant $Y_{t-1}$ est $\mathcal N(0, F_t)$. Cette loi conditionnelle ne dépend pas de $Y_{t-1}$, puisque $F_t$ n'est pas aléatoire. L'innovation $v_t$ est donc indépendante de $Y_{t-1}$, et sa loi est $\mathcal N(0, F_t)$. Les innovations passées $v_1, \dots, v_{t-1}$ sont des fonctions de $Y_{t-1}$, dont $v_t$ est indépendante. En appliquant cet argument pour $t = n, n-1, \dots, 2$, la densité jointe de $(v_1, \dots, v_n)$ est le produit des densités marginales. #+END_proof L'innovation $v_t$ est la partie de $y_t$ qui n'était pas prévisible à la date $t-1$. Comme $v_t$ est égale à $y_t$ moins une fonction de $Y_{t-1}$, la suite des innovations jusqu'à la date $t$ et celle des observations se déduisent l'une de l'autre\nbsp{}: elles portent la même information. Si le modèle est bien spécifié, les /innovations standardisées/ \(e_t = F_t^{-1/2}v_t\) sont indépendantes et de loi normale centrée réduite. Leurs autocorrélations empiriques fournissent donc un diagnostic simple de la spécification, dont l'application fera un large usage. ** Initialisation :PROPERTIES: :CUSTOM_ID: initialisation :END: Il reste à choisir $a_0$ et $P_0$. Si le modèle est stationnaire, avec des matrices constantes et des valeurs propres de $T$ de module strictement inférieur à un, on tire $\alpha_0$ dans la loi stationnaire de l'état\nbsp{}: \(a_0 = (I_m - T)^{-1}c\) et $P_0$ est la solution de l'équation de Lyapunov \begin{equation*} P_0 = T P_0 T' + R Q R',\qquad\text{soit}\qquad \mathrm{vec}(P_0) = (I_{m^2} - T\otimes T)^{-1}\,\mathrm{vec}(RQR'), \end{equation*} que calcule la fonction =solve_discrete_lyapunov= de SciPy. Si l'état a des composantes non stationnaires, comme le niveau d'une marche aléatoire, cette loi stationnaire n'existe pas. On traduit alors l'ignorance sur l'état initial par une loi très dispersée, $a_0 = 0$ et $P_0 = \kappa I_m$ avec $\kappa$ grand\nbsp{}: c'est l'/initialisation diffuse approchée/. Dans le modèle de niveau local, la première étape du filtre donne \(P_{1|0} = \kappa + \sigma_\eta^2\), puis \begin{equation*} K_1 = \frac{P_{1|0}}{P_{1|0} + \sigma_\varepsilon^2},\qquad a_{1|1} = K_1 y_1,\qquad P_{1|1} = \frac{\sigma_\varepsilon^2 P_{1|0}}{P_{1|0} + \sigma_\varepsilon^2}. \end{equation*} Lorsque $\kappa$ tend vers l'infini, $a_{1|1}$ tend vers $y_1$ et $P_{1|1}$ vers \(\sigma_\varepsilon^2\)\nbsp{}: la première observation fixe le niveau, avec la précision de la mesure, et la loi initiale est oubliée. Plus généralement, si $d$ composantes de l'état sont diffuses, les $d$ premières observations servent à les déterminer, après quoi l'effet de $\kappa$ est d'ordre $1/\kappa$. Trois précautions s'imposent. - L'approximation est d'autant meilleure que $\kappa$ est grand devant la variance des données et devant le carré de leur écart à $a_0$. Avec des données de l'ordre de $1\,000$, comme dans l'application, $\kappa$ doit être bien supérieur à $10^6$. - La variance $P_{t|t}$ des premières étapes est la différence de deux termes d'ordre $\kappa$, et le calcul perd environ $\log_{10}\kappa$ chiffres significatifs sur les seize de l'arithmétique flottante. La forme de Joseph préserve la symétrie et la positivité, mais une valeur excessive de $\kappa$ dégrade la précision. On retient $\kappa = 10^7$ pour les simulations et $\kappa = 10^9$ pour l'application, après vérification. - Les variances $F_t$ des $d$ premières innovations sont d'ordre \(\kappa\)\nbsp{}: ces innovations ne portent aucune information sur les paramètres, et leur contribution à la vraisemblance dépend de la valeur arbitraire de $\kappa$. Il faut les écarter, comme on le verra dans la [[#concentree][section sur l'estimation]]. #+BEGIN_remarque L'/initialisation diffuse exacte/ traite la limite $\kappa \to \infty$ analytiquement, en séparant dans $P_{t|t-1}$ un terme proportionnel à $\kappa$ et un terme fini (De Jong, /Annals of Statistics/, 1991\nbsp{}; Koopman, /Journal of the American Statistical Association/, 1997\nbsp{}; Durbin et Koopman, 2012, chapitre 5). Elle supprime l'arbitraire du choix de $\kappa$ au prix de récurrences plus lourdes pendant les premières périodes. La bibliothèque =statsmodels= la met en œuvre\nbsp{}; elle servira de contrôle externe dans l'application. #+END_remarque ** Une illustration :PROPERTIES: :CUSTOM_ID: illustration :END: On simule $n = 100$ observations d'un modèle de niveau local, avec $\sigma_\varepsilon = 1$ et $\sigma_\eta = 0{,}5$, et on applique le filtre avec une initialisation diffuse approchée. #+begin_src python :session kalman :exports code :results none n = 100 sigma_eps, sigma_eta = 1.0, 0.5 mu = np.cumsum(sigma_eta*rng.standard_normal(n)) y_sim = mu + sigma_eps*rng.standard_normal(n) kappa = 1e7 Z, T, R, H, Q = niveau_local(sigma_eps**2, sigma_eta**2) res_sim = filtre_kalman(y_sim, Z, T, R, H, Q, np.zeros(1), kappa*np.eye(1)) rmse = lambda x: np.sqrt(np.mean((x - mu)**2)) print(rmse(y_sim), rmse(res_sim['a_filt'][:, 0])) #+end_src L'état filtré estime le niveau avec une erreur quadratique moyenne de $0{,}61$, contre $1{,}01$ pour l'observation elle-même prise comme estimateur naïf. La figure [[fig:niveau-local-filtre][ci-dessous]] montre que l'état filtré suit le niveau avec un léger retard\nbsp{}: n'utilisant que le passé, il ne peut distinguer une variation durable du niveau d'un bruit de mesure qu'après quelques observations. #+begin_src python :session kalman :exports none :results none t_sim = np.arange(1, n+1) a_f, s_f = res_sim['a_filt'][:, 0], np.sqrt(res_sim['P_filt'][:, 0, 0]) fig, ax = plt.subplots(figsize=(6, 4)) ax.plot(t_sim, y_sim, 'k.', markersize=3, label=r'$y_t$') ax.plot(t_sim, mu, 'k', linewidth=0.8, label=r'$\mu_t$') ax.plot(t_sim, a_f, 'b', linewidth=1, label=r'$a_{t|t}$') ax.fill_between(t_sim, a_f-2*s_f, a_f+2*s_f, color='b', alpha=0.15, linewidth=0) ax.set_xlabel(r'$t$') ax.legend() fig.tight_layout() fig.savefig("kalman-niveau-local-filtre.svg", transparent=True) #+end_src #+CAPTION: *Modèle de niveau local simulé ($\sigma_\varepsilon = 1$, $\sigma_\eta = 0{,}5$)\nbsp{}: observations, niveau et état filtré, avec une bande de plus ou moins deux écarts-types conditionnels.* #+LABEL: fig:niveau-local-filtre [[file:kalman-niveau-local-filtre.svg]] * Convergence du filtre :PROPERTIES: :CUSTOM_ID: convergence :END: Lorsque les matrices du système sont constantes, la récurrence sur les variances ne dépend ni des observations ni de la date. En reportant l'étape de mise à jour dans l'étape de prédiction, on obtient une récurrence sur la seule variance de prédiction. #+BEGIN_corollary Avec des matrices constantes, la variance de prédiction vérifie l'/équation de Riccati/ \begin{equation*} P_{t+1|t} = T P_{t|t-1} T' - T P_{t|t-1} Z' F_t^{-1} Z P_{t|t-1} T' + RQR', \qquad F_t = Z P_{t|t-1} Z' + H, \end{equation*} et l'état prédit vérifie \(a_{t+1|t} = T a_{t|t-1} + c + T K_t v_t\). #+END_corollary #+BEGIN_proof Il suffit de reporter $a_{t|t} = a_{t|t-1} + K_t v_t$ et \(P_{t|t} = P_{t|t-1} - P_{t|t-1}Z'F_t^{-1}ZP_{t|t-1}\) dans les équations de prédiction de la date $t+1$. #+END_proof La suite des variances de prédiction converge sous des conditions très générales. On admet le résultat suivant (Anderson et Moore, /Optimal Filtering/, 1979, chapitre 4, section 4.4). #+BEGIN_proposition Supposons $H$ définie positive, la paire $(T, Z)$ détectable et la paire $(T, RQ^{1/2})$ stabilisable. Alors, pour toute variance initiale semi-définie positive, $P_{t+1|t}$ converge vers l'unique solution semi-définie positive $\bar P$ de l'équation de Riccati algébrique \begin{equation*} \bar P = T\bar PT' - T\bar PZ'(Z\bar PZ' + H)^{-1}Z\bar PT' + RQR', \end{equation*} et le gain $K_t$ converge vers \(\bar K = \bar PZ'\bar F^{-1}\), avec \(\bar F = Z\bar PZ' + H\). #+END_proposition La détectabilité exige que les composantes instables de l'état se reflètent dans les observations, la stabilisabilité que les chocs atteignent toutes ces composantes. Une fois le régime permanent atteint, le filtre est un filtre linéaire invariant, \(a_{t+1|t} = T(I_m - \bar KZ)a_{t|t-1} + T\bar Ky_t\), et le calcul des variances devient inutile. La matrice $\bar P$ est donnée par la fonction =solve_discrete_are= de SciPy, dont la convention transpose celle du filtre\nbsp{}: =solve_discrete_are(T.T, Z.T, R @ Q @ R.T, H)=. ** Le cas du niveau local :PROPERTIES: :CUSTOM_ID: niveau-local-riccati :END: Dans le modèle de niveau local, tout se calcule explicitement. On note \(q = \sigma_\eta^2/\sigma_\varepsilon^2\) le rapport signal sur bruit et \(p_t = P_{t|t-1}/\sigma_\varepsilon^2\) la variance de prédiction rapportée à celle du bruit de mesure. #+BEGIN_property La suite $p_t$ vérifie $p_{t+1} = f(p_t)$, avec \(f(p) = p/(1+p) + q\). Pour tout $p_1 \geq 0$, elle converge de façon monotone vers l'unique point fixe positif \begin{equation*} \bar p = \frac{q + \sqrt{q^2 + 4q}}{2}, \end{equation*} et le gain \(K_t = p_t/(1+p_t)\) converge vers \(\bar K = \bar p/(1 + \bar p)\). #+END_property #+BEGIN_proof Avec $Z = T = R = 1$, l'équation de Riccati s'écrit \(P_{t+1|t} = P_{t|t-1} - P_{t|t-1}^2/(P_{t|t-1} + \sigma_\varepsilon^2) + \sigma_\eta^2\), soit, en divisant par $\sigma_\varepsilon^2$, \(p_{t+1} = p_t - p_t^2/(1 + p_t) + q = p_t/(1+p_t) + q\). Les points fixes annulent le polynôme $p^2 - qp - q$, dont $\bar p$ est la seule racine positive. La fonction $f$ est croissante sur $[0, \infty[$, et la fonction \(g(p) = f(p) - p = q - p^2/(1+p)\) est décroissante et s'annule en $\bar p$. Si $p_t < \bar p$, on a donc \(p_t < f(p_t) < f(\bar p) = \bar p\)\nbsp{}: la suite est croissante et majorée par $\bar p$. Symétriquement, elle est décroissante et minorée par $\bar p$ si $p_t > \bar p$. Dans les deux cas elle converge, et sa limite est un point fixe de $f$, c'est-à-dire $\bar p$. #+END_proof Au voisinage du point fixe, l'écart à $\bar p$ est multiplié à chaque période par \(f'(\bar p) = (1 + \bar p)^{-2}\)\nbsp{}: la convergence est géométrique, d'autant plus rapide que le rapport signal sur bruit est élevé. La figure [[fig:gain][ci-dessous]] le vérifie pour trois valeurs de $q$, avec l'initialisation diffuse approchée. Le gain part de un, puisque la première observation fixe le niveau, et rejoint sa valeur stationnaire, $0{,}200$, $0{,}390$ et $0{,}618$ pour $q$ égal à $0{,}05$, $0{,}25$ et $1$, à $10^{-4}$ près après respectivement $19$, $10$ et $6$ observations. Pour $q = 1$, $\bar p$ est le nombre d'or et $\bar K$ son inverse. #+begin_src python :session kalman :exports code :results none def point_fixe_niveau_local(q): p_bar = (q + np.sqrt(q**2 + 4*q))/2 return p_bar, p_bar/(1 + p_bar) for q in (0.05, 0.25, 1): r = filtre_kalman(np.zeros(30), *niveau_local(1.0, q), np.zeros(1), kappa*np.eye(1)) K_bar = point_fixe_niveau_local(q)[1] print(q, K_bar, 1 + np.argmax(np.abs(r['K'][:, 0, 0] - K_bar) < 1e-4)) #+end_src #+begin_src python :session kalman :exports none :results none fig, axes = plt.subplots(1, 2, figsize=(12, 4)) dates = np.arange(1, 31) for q, c in ((0.05, 'b'), (0.25, 'g'), (1, 'r')): r = filtre_kalman(np.zeros(30), *niveau_local(1.0, q), np.zeros(1), kappa*np.eye(1)) p_bar, K_bar = point_fixe_niveau_local(q) axes[0].plot(dates, r['P_pred'][:, 0, 0], c+'o-', markersize=3, linewidth=1, label=fr'$q = {virgule(q)}$') axes[0].axhline(p_bar, color=c, linestyle='--', linewidth=0.8) axes[1].plot(dates, r['K'][:, 0, 0], c+'o-', markersize=3, linewidth=1, label=fr'$q = {virgule(q)}$') axes[1].axhline(K_bar, color=c, linestyle='--', linewidth=0.8) axes[0].set_yscale('log') axes[0].set_ylim(0.1, 10) axes[0].set_xlabel(r'$t$') axes[0].set_ylabel(r'$P_{t|t-1}/\sigma_\varepsilon^2$') axes[0].legend() axes[1].set_xlabel(r'$t$') axes[1].set_ylabel(r'$K_t$') axes[1].legend() fig.tight_layout() fig.savefig("kalman-gain.svg", transparent=True) #+end_src #+CAPTION: *Convergence de la variance de prédiction (à gauche, échelle logarithmique) et du gain (à droite) dans le modèle de niveau local, pour trois valeurs du rapport signal sur bruit. Les pointillés indiquent les valeurs stationnaires $\bar p$ et $\bar K$.* #+LABEL: fig:gain [[file:kalman-gain.svg]] ** Forme réduite et lissage exponentiel :PROPERTIES: :CUSTOM_ID: forme-reduite :END: Le régime permanent du filtre a une interprétation remarquable dans le modèle de niveau local, qui passe par la forme réduite de ce modèle. #+BEGIN_property Dans le modèle de niveau local, la différence première \(\Delta y_t = \eta_t + \varepsilon_t - \varepsilon_{t-1}\) est un processus MA(1) inversible, \(\Delta y_t = \xi_t + \theta\xi_{t-1}\), où $\xi_t$ est un bruit blanc de variance \(\sigma_\xi^2 = -\sigma_\varepsilon^2/\theta\) et \begin{equation*} \theta = \frac{\sqrt{q^2 + 4q} - q - 2}{2} \in \left]-1, 0\right[. \end{equation*} Le processus $y_t$ est donc un ARIMA(0,1,1). #+END_property #+BEGIN_proof Les autocovariances de $\Delta y_t$ sont \(\gamma_0 = \sigma_\eta^2 + 2\sigma_\varepsilon^2\), \(\gamma_1 = -\sigma_\varepsilon^2\) et $\gamma_k = 0$ pour \(k \geq 2\)\nbsp{}: ce sont celles d'un processus MA(1). Celles de $\xi_t + \theta\xi_{t-1}$ sont \(\gamma_0 = (1 + \theta^2)\sigma_\xi^2\) et \(\gamma_1 = \theta\sigma_\xi^2\). En égalant les autocorrélations d'ordre un, \(\theta/(1 + \theta^2) = -1/(q + 2)\), soit \(\theta^2 + (q + 2)\theta + 1 = 0\). Le discriminant, $q^2 + 4q$, est positif, les deux racines sont négatives et leur produit vaut un\nbsp{}: une seule est comprise entre $-1$ et $0$, c'est la racine inversible. Enfin, \(\sigma_\xi^2 = \gamma_1/\theta = -\sigma_\varepsilon^2/\theta\). #+END_proof #+BEGIN_property Le gain stationnaire vaut $\bar K = 1 + \theta$, et la variance stationnaire de l'innovation, \(\bar F = \sigma_\varepsilon^2(1 + \bar p)\), est égale à $\sigma_\xi^2$. En régime permanent, la prévision suit la récurrence du /lissage exponentiel/, \begin{equation*} a_{t+1|t} = (1 - \bar K)\,a_{t|t-1} + \bar K y_t, \end{equation*} et les innovations du filtre sont celles de la forme réduite\nbsp{}: \(\Delta y_t = v_t + \theta v_{t-1}\). #+END_property #+BEGIN_proof Notons $r = \sqrt{q^2 + 4q}$, de sorte que $\bar p = (q + r)/2$ et $1 + \theta = (r - q)/2$. En multipliant numérateur et dénominateur par $q + 2 + r$, et puisque $r^2 = q^2 + 4q$, \begin{equation*} -\frac{1 + \theta}{\theta} = \frac{r - q}{q + 2 - r} = \frac{(r - q)(q + 2 + r)}{(q + 2)^2 - r^2} = \frac{2q + 2r}{4} = \bar p. \end{equation*} Il en résulte $1 + \bar p = -1/\theta$, puis \(\bar K = \bar p/(1 + \bar p) = 1 + \theta\) et \(\bar F = \sigma_\varepsilon^2(1 + \bar p) = -\sigma_\varepsilon^2/\theta = \sigma_\xi^2\). En régime permanent, avec $Z = T = 1$, l'état prédit est \(a_{t+1|t} = a_{t|t} = a_{t|t-1} + \bar K(y_t - a_{t|t-1})\), qui est la récurrence annoncée. Enfin, $y_t = a_{t|t-1} + v_t$ et \(a_{t|t-1} - a_{t-1|t-2} = \bar K v_{t-1}\) donnent \begin{equation*} \Delta y_t = \bar K v_{t-1} + v_t - v_{t-1} = v_t - (1 - \bar K)v_{t-1} = v_t + \theta v_{t-1}. \end{equation*} #+END_proof Le filtre de Kalman en régime permanent est donc la méthode de prévision par lissage exponentiel, et ce lissage est la prévision optimale d'un processus ARIMA(0,1,1) (Muth, /Journal of the American Statistical Association/, 1960). Le filtre apporte deux choses de plus\nbsp{}: la constante de lissage se déduit des paramètres du modèle, et le gain varie pendant la phase transitoire pour tenir compte de l'incertitude initiale. On le vérifie sur la série simulée, avec $q = 0{,}25$, en comparant la prédiction du filtre avec un lissage exponentiel de constante $\bar K$ initialisé à la première observation\nbsp{}: #+begin_src python :session kalman :exports code :results none q = sigma_eta**2/sigma_eps**2 p_bar, K_bar = point_fixe_niveau_local(q) theta = (np.sqrt(q**2 + 4*q) - q - 2)/2 print(K_bar, 1 + theta) lissage = np.zeros(n) lissage[1] = y_sim[0] for t in range(1, n-1): lissage[t+1] = (1 - K_bar)*lissage[t] + K_bar*y_sim[t] ecart = np.abs(lissage[1:] - res_sim['a_pred'][1:, 0]) print(ecart[[3, 8, 18]]) #+end_src L'écart entre les deux prédictions, de l'ordre de $2\times 10^{-2}$ à la date $5$, n'est plus que de $3\times 10^{-3}$ à la date $10$ et $2\times 10^{-5}$ à la date \(20\)\nbsp{}: il décroît géométriquement, au taux $1 - \bar K = -\theta \approx 0{,}61$ par période. Le panneau droit de la figure [[fig:lissage-exponentiel][ci-dessous]] vérifie par ailleurs que les innovations standardisées $e_t$ ne sont pas autocorrélées, comme elles doivent l'être lorsque le modèle est bien spécifié. La fonction d'autocorrélation empirique servira encore dans l'application. #+begin_src python :session kalman :exports code :results none def acf(x, kmax): x = x - x.mean() return np.array([np.sum(x[k:]*x[:-k]) for k in range(1, kmax+1)])/np.sum(x**2) e_sim = res_sim['v'][1:, 0]/np.sqrt(res_sim['F'][1:, 0, 0]) print(acf(e_sim, 10)) #+end_src #+begin_src python :session kalman :exports none :results none fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].semilogy(np.arange(2, 41), ecart[:39], 'b', linewidth=1) axes[0].set_xlabel(r'$t$') axes[0].set_ylabel('écart entre les deux prédictions') k = np.arange(1, 11) bande = 1.96/np.sqrt(len(e_sim)) axes[1].bar(k, acf(e_sim, 10), color='b', width=0.5) for s in (-1, 1): axes[1].axhline(s*bande, color='k', linestyle='--', linewidth=0.8) axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xticks(k) axes[1].set_xlabel('retard') axes[1].set_ylabel(r'autocorrélation de $e_t$') fig.tight_layout() fig.savefig("kalman-lissage-exponentiel.svg", transparent=True) #+end_src #+CAPTION: *À gauche, écart en valeur absolue entre la prédiction du filtre $a_{t|t-1}$ et le lissage exponentiel de constante $\bar K$ (échelle logarithmique). À droite, autocorrélations des innovations standardisées, avec la bande $\pm 1{,}96/\sqrt{n}$.* #+LABEL: fig:lissage-exponentiel [[file:kalman-lissage-exponentiel.svg]] * Le lisseur :PROPERTIES: :CUSTOM_ID: lisseur :END: Le filtre estime l'état à la date $t$ avec l'information disponible à cette date. Lorsque tout l'échantillon est observé, il est naturel d'utiliser aussi les observations postérieures\nbsp{}: c'est l'objet du /lissage/, qui calcule $a_{t|n}$ et $P_{t|n}$ pour $t = 1, \dots, n$. Le filtre est unilatéral, le lisseur bilatéral. Le point de départ est une propriété de Markov\nbsp{}: une fois connu l'état à la date $t+1$, les observations postérieures n'apportent plus rien sur l'état à la date $t$. #+BEGIN_lemma Pour $t < n$, la loi de $\alpha_t$ sachant $\alpha_{t+1}$ et $Y_n$ est égale à la loi de $\alpha_t$ sachant $\alpha_{t+1}$ et $Y_t$. #+END_lemma #+BEGIN_proof Notons $Y_{t+1:n} = (y_{t+1}, \dots, y_n)$ les observations postérieures à la date $t$. D'après les équations du modèle, elles s'écrivent comme une fonction de $\alpha_{t+1}$ et des perturbations \(\varepsilon_{t+1}, \dots, \varepsilon_n, \eta_{t+2}, \dots, \eta_n\), que l'on regroupe dans un vecteur $\omega$. Le triplet formé par $\alpha_t$, $\alpha_{t+1}$ et $Y_t$ est une fonction de $\alpha_0$, de \(\varepsilon_1, \dots, \varepsilon_t\) et de \(\eta_1, \dots, \eta_{t+1}\), dont $\omega$ est indépendant. Sachant $\alpha_t$, $\alpha_{t+1}$ et $Y_t$, la loi de $Y_{t+1:n}$ est donc celle d'une fonction de $\alpha_{t+1}$ et de \(\omega\)\nbsp{}: elle ne dépend que de $\alpha_{t+1}$. Par la formule de Bayes, en notant $p$ les densités, \begin{equation*} p(\alpha_t \mid \alpha_{t+1}, Y_n) \propto p(Y_{t+1:n} \mid \alpha_t, \alpha_{t+1}, Y_t)\, p(\alpha_t \mid \alpha_{t+1}, Y_t) = p(Y_{t+1:n} \mid \alpha_{t+1})\, p(\alpha_t \mid \alpha_{t+1}, Y_t), \end{equation*} où le symbole $\propto$ indique la proportionnalité en tant que fonctions de $\alpha_t$. Le premier facteur ne dépend pas de \(\alpha_t\)\nbsp{}: la densité de $\alpha_t$ sachant $\alpha_{t+1}$ et $Y_n$ est proportionnelle, donc égale, à celle de $\alpha_t$ sachant $\alpha_{t+1}$ et $Y_t$. #+END_proof #+BEGIN_proposition Partant de $a_{n|n}$ et $P_{n|n}$, calculés par le filtre, les moments lissés s'obtiennent par la récurrence rétrograde, pour $t = n-1, n-2, \dots, 1$, \begin{equation*} \begin{aligned} J_t &= P_{t|t} T_{t+1}' P_{t+1|t}^{-1},\\ a_{t|n} &= a_{t|t} + J_t\left(a_{t+1|n} - a_{t+1|t}\right),\\ P_{t|n} &= P_{t|t} + J_t\left(P_{t+1|n} - P_{t+1|t}\right)J_t', \end{aligned} \end{equation*} en supposant $P_{t+1|t}$ inversible. La loi de $\alpha_t$ sachant $Y_n$ est normale, d'espérance $a_{t|n}$ et de variance $P_{t|n}$. #+END_proposition Cette récurrence est due à Rauch, Tung et Striebel (/AIAA Journal/, 1965). Elle ne demande qu'une passe arrière sur les résultats du filtre. #+BEGIN_proof /Loi jointe./ Sachant $Y_t$, l'état $\alpha_t$ suit la loi $\mathcal N(a_{t|t}, P_{t|t})$ et \(\alpha_{t+1} = T_{t+1}\alpha_t + c_{t+1} + R_{t+1}\eta_{t+1}\), où $\eta_{t+1}$ est indépendant de $\alpha_t$ et de $Y_t$. Sachant $Y_t$, le couple formé par $\alpha_t$ et $\alpha_{t+1}$ est donc gaussien\nbsp{}: \begin{equation*} \begin{pmatrix} \alpha_t\\ \alpha_{t+1} \end{pmatrix} \Bigm| Y_t \sim \mathcal N\left(\begin{pmatrix} a_{t|t}\\ a_{t+1|t} \end{pmatrix}, \begin{pmatrix} P_{t|t} & P_{t|t}T_{t+1}'\\ T_{t+1}P_{t|t} & P_{t+1|t} \end{pmatrix}\right). \end{equation*} /Conditionnement par l'état suivant./ Le lemme sur la loi normale donne \begin{equation*} \alpha_t \mid \alpha_{t+1}, Y_t \sim \mathcal N\left(a_{t|t} + J_t(\alpha_{t+1} - a_{t+1|t}),\; P_{t|t} - J_tP_{t+1|t}J_t'\right), \end{equation*} et, d'après le lemme précédent, c'est aussi la loi de $\alpha_t$ sachant $\alpha_{t+1}$ et $Y_n$. /Espérance lissée./ Par la loi des espérances itérées, \begin{equation*} a_{t|n} = \mathbb E\left[\mathbb E[\alpha_t \mid \alpha_{t+1}, Y_n] \mid Y_n\right] = a_{t|t} + J_t\left(a_{t+1|n} - a_{t+1|t}\right). \end{equation*} /Variance lissée./ Par la formule de la variance totale, \begin{equation*} \begin{aligned} P_{t|n} &= \mathbb E\left[\mathbb V[\alpha_t \mid \alpha_{t+1}, Y_n] \mid Y_n\right] + \mathbb V\left[\mathbb E[\alpha_t \mid \alpha_{t+1}, Y_n] \mid Y_n\right]\\ &= P_{t|t} - J_tP_{t+1|t}J_t' + J_tP_{t+1|n}J_t'. \end{aligned} \end{equation*} Enfin, la loi de $\alpha_t$ sachant $Y_n$ est normale parce que $\alpha_t$ et $Y_n$ forment un vecteur gaussien. #+END_proof #+BEGIN_remarque La même formule de la variance totale, appliquée en conditionnant par $Y_t$ plutôt que par $\alpha_{t+1}$, donne \(P_{t|t} = P_{t|n} + \mathbb V\left[a_{t|n} \mid Y_t\right]\)\nbsp{}: la variance lissée est inférieure à la variance filtrée, au sens des matrices semi-définies positives. Lorsque $P_{t+1|t}$ est singulière, ce qui arrive quand l'état contient des composantes observées sans erreur, on peut remplacer l'inverse par un inverse généralisé ou utiliser les récurrences de De Jong (/Journal of the American Statistical Association/, 1989), qui évitent toute inversion. #+END_remarque #+begin_src python :session kalman :exports code :results none def lisseur_kalman(res, T): a_liss, P_liss = res['a_filt'].copy(), res['P_filt'].copy() for t in range(len(a_liss) - 2, -1, -1): J = np.linalg.solve(res['P_pred'][t+1], T @ res['P_filt'][t]).T # P_{t|t} T' P_{t+1|t}^{-1} a_liss[t] = res['a_filt'][t] + J @ (a_liss[t+1] - res['a_pred'][t+1]) P_liss[t] = res['P_filt'][t] + J @ (P_liss[t+1] - res['P_pred'][t+1]) @ J.T return a_liss, P_liss a_liss, P_liss = lisseur_kalman(res_sim, T) print(rmse(a_liss[:, 0])) print(res_sim['P_filt'][50, 0, 0], P_liss[50, 0, 0]) #+end_src Sur la série simulée, le lisseur réduit l'erreur quadratique moyenne de $0{,}61$ à $0{,}48$. Au milieu de l'échantillon, la variance lissée vaut $0{,}243$ contre $0{,}390$ pour la variance filtrée\nbsp{}: la bande de confiance est plus étroite d'un cinquième environ, sauf aux extrémités de l'échantillon, où le lisseur ne dispose pas d'observations de part et d'autre et rejoint le filtre à la date $n$. La figure [[fig:niveau-local-lisseur][ci-dessous]] montre aussi que le lisseur corrige le retard du filtre\nbsp{}: il anticipe les variations du niveau, puisqu'il voit les observations suivantes. #+begin_src python :session kalman :exports none :results none s_s = np.sqrt(P_liss[:, 0, 0]) fig, ax = plt.subplots(figsize=(6, 4)) ax.plot(t_sim, mu, 'k', linewidth=0.8, label=r'$\mu_t$') ax.plot(t_sim, a_f, 'b', linewidth=1, label=r'$a_{t|t}$') ax.fill_between(t_sim, a_f-2*s_f, a_f+2*s_f, color='b', alpha=0.12, linewidth=0) ax.plot(t_sim, a_liss[:, 0], 'r', linewidth=1, label=r'$a_{t|n}$') ax.fill_between(t_sim, a_liss[:, 0]-2*s_s, a_liss[:, 0]+2*s_s, color='r', alpha=0.2, linewidth=0) ax.set_xlabel(r'$t$') ax.legend() fig.tight_layout() fig.savefig("kalman-niveau-local-lisseur.svg", transparent=True) #+end_src #+CAPTION: *Niveau simulé, état filtré et état lissé, avec leurs bandes de plus ou moins deux écarts-types conditionnels.* #+LABEL: fig:niveau-local-lisseur [[file:kalman-niveau-local-lisseur.svg]] * Estimation par le maximum de vraisemblance :PROPERTIES: :CUSTOM_ID: estimation :END: Les matrices du système dépendent en général de paramètres inconnus, regroupés dans un vecteur \(\psi\)\nbsp{}: les variances du modèle de niveau local, les coefficients et la variance d'un processus ARMA. Le filtre de Kalman donne la vraisemblance de ces paramètres presque sans calcul supplémentaire. ** Décomposition de l'erreur de prévision :PROPERTIES: :CUSTOM_ID: decomposition :END: #+BEGIN_proposition La log-vraisemblance des observations $y_1, \dots, y_n$ s'écrit \begin{equation*} \log L(\psi) = -\frac{np}{2}\log 2\pi - \frac12\sum_{t=1}^n \log\det F_t - \frac12\sum_{t=1}^n v_t'F_t^{-1}v_t, \end{equation*} où les innovations $v_t$ et leurs variances $F_t$ sont calculées par le filtre avec la valeur $\psi$ des paramètres. #+END_proposition #+BEGIN_proof La densité jointe se factorise en un produit de densités conditionnelles, \begin{equation*} f(y_1, \dots, y_n) = \prod_{t=1}^n f(y_t \mid Y_{t-1}), \end{equation*} avec la convention $f(y_1 \mid Y_0) = f(y_1)$. D'après la preuve du filtre, la loi de $y_t$ sachant $Y_{t-1}$ est normale, d'espérance $Z_t a_{t|t-1} + d_t$ et de variance $F_t$, et sa densité en $y_t$ vaut \begin{equation*} f(y_t \mid Y_{t-1}) = (2\pi)^{-p/2}(\det F_t)^{-1/2}\exp\left(-\frac12 v_t'F_t^{-1}v_t\right). \end{equation*} Il reste à prendre le logarithme du produit. #+END_proof Le calcul direct de la vraisemblance demanderait d'inverser la matrice de variance de l'échantillon, de taille $np \times np$, pour un coût d'ordre $n^3p^3$. Le filtre en calcule implicitement une factorisation triangulaire, pour un coût proportionnel à $n$. Pour un processus ARMA initialisé par sa loi stationnaire, c'est la vraisemblance /exacte/, qui tient compte de la loi des premières observations, et non la vraisemblance conditionnelle aux premières observations que maximisent les moindres carrés (voir la note sur le [[https://stephane-adjemian.fr/posts/biais-de-l-estimateur-mco-d-un-processus-ar1/][biais de l'estimateur des moindres carrés d'un AR(1)]] et l'[[ex-h-nul][exercice]] consacré au cas autorégressif). Le code prévoit d'écarter les $d$ premières innovations, pour la raison indiquée plus bas\nbsp{}: #+begin_src python :session kalman :exports code :results none def log_vraisemblance(res, d=0): v, F = res['v'][d:, 0], res['F'][d:, 0, 0] ok = ~np.isnan(v) return -0.5*np.sum(np.log(2*np.pi*F[ok]) + v[ok]**2/F[ok]) #+end_src ** Vraisemblance concentrée :PROPERTIES: :CUSTOM_ID: concentree :END: Dans les modèles à composantes inobservées, les paramètres sont souvent des variances, et l'une d'elles peut être éliminée analytiquement. On suppose $p = 1$ et que les paramètres se décomposent en un facteur d'échelle $\sigma^2$ et un vecteur $\psi$, avec $H = \sigma^2H_*(\psi)$, $Q = \sigma^2Q_*(\psi)$ et $P_0 = \sigma^2P_{0*}(\psi)$. On note $v_t^*$ et $F_t^*$ les quantités calculées par le filtre avec $\sigma^2 = 1$, et $N$ le nombre d'innovations prises en compte dans la vraisemblance. #+BEGIN_property Les innovations ne dépendent pas de $\sigma^2$, $v_t = v_t^*$, et $F_t = \sigma^2F_t^*$. La log-vraisemblance est maximale en $\sigma^2$ pour \begin{equation*} \hat\sigma^2(\psi) = \frac1N\sum_t \frac{(v_t^*)^2}{F_t^*}, \end{equation*} et la /log-vraisemblance concentrée/, obtenue en remplaçant $\sigma^2$ par $\hat\sigma^2(\psi)$, vaut \begin{equation*} \log L_c(\psi) = -\frac N2\left(\log 2\pi + 1\right) - \frac12\sum_t\log F_t^* - \frac N2\log\hat\sigma^2(\psi). \end{equation*} #+END_property #+BEGIN_proof Par récurrence, si $P_{t-1|t-1} = \sigma^2P_{t-1|t-1}^*$, les équations du filtre donnent $P_{t|t-1} = \sigma^2P_{t|t-1}^*$, $F_t = \sigma^2F_t^*$ et \(K_t = P_{t|t-1}Z'F_t^{-1} = K_t^*\)\nbsp{}: le gain, et donc les états prédits et les innovations, ne dépendent pas de $\sigma^2$, tandis que $P_{t|t} = \sigma^2P_{t|t}^*$. La log-vraisemblance s'écrit alors \begin{equation*} \log L = -\frac N2\log 2\pi - \frac N2\log\sigma^2 - \frac12\sum_t\log F_t^* - \frac{1}{2\sigma^2}\sum_t\frac{(v_t^*)^2}{F_t^*}. \end{equation*} Vue comme une fonction de $1/\sigma^2$, elle est concave, et sa dérivée s'annule en $\hat\sigma^2(\psi)$. En reportant, le dernier terme vaut $-N/2$. #+END_proof Avec l'initialisation diffuse approchée, $P_0 = \kappa I_m$ n'est pas proportionnelle à $\sigma^2$, mais l'écart est d'ordre $1/\kappa$. Surtout, les $d$ premières innovations, dont la variance est d'ordre $\kappa$, contribuent à la vraisemblance par des termes $-\frac12\log F_t$ qui dépendent de la valeur arbitraire de \(\kappa\)\nbsp{}: on les écarte, et les sommes portent sur les dates $t = d+1, \dots, n$, avec $N = n - d$. C'est la /vraisemblance diffuse/ (Harvey, 1989, section 3.4.3). Elle diffère de la vraisemblance calculée avec l'initialisation diffuse exacte par une constante qui ne dépend pas des paramètres, pourvu que la partie diffuse du modèle, dans $Z$ et $T$, n'en dépende pas non plus, comme dans les modèles de tendance de cette note (Francke, Koopman et De Vos, /Journal of Time Series Analysis/, 2010)\nbsp{}: les deux donnent alors les mêmes estimations, ce que l'on vérifiera dans l'application. #+begin_src python :session kalman :exports code :results none def vraisemblance_concentree(res, d=0): v, F = res['v'][d:, 0], res['F'][d:, 0, 0] ok = ~np.isnan(v) N = ok.sum() s2 = np.mean(v[ok]**2/F[ok]) return -0.5*N*(np.log(2*np.pi) + 1) - 0.5*np.sum(np.log(F[ok])) - 0.5*N*np.log(s2), s2 #+end_src ** Précision des estimateurs et tests :PROPERTIES: :CUSTOM_ID: erreurs-standard :END: Sous des conditions de régularité, qui supposent notamment que la vraie valeur des paramètres est intérieure à l'espace des paramètres, l'estimateur du maximum de vraisemblance est asymptotiquement normal, et sa matrice de variance est estimée par l'inverse de l'opposé de la hessienne de la log-vraisemblance au maximum. La hessienne se calcule par différences finies centrées\nbsp{}: \begin{equation*} \begin{aligned} \frac{\partial^2 \log L}{\partial\psi_i\partial\psi_j} \approx \frac{1}{4h^2}\Big[ &\log L(\psi + he_i + he_j) - \log L(\psi + he_i - he_j)\\ &- \log L(\psi - he_i + he_j) + \log L(\psi - he_i - he_j)\Big], \end{aligned} \end{equation*} où $e_i$ est le \(i\)-ème vecteur de la base canonique. #+begin_src python :session kalman :exports code :results none def hessienne(f, x, h=1e-3): x = np.atleast_1d(np.asarray(x, dtype=float)) E = h*np.eye(len(x)) return np.array([[(f(x+ei+ej) - f(x+ei-ej) - f(x-ei+ej) + f(x-ei-ej))/(4*h**2) for ej in E] for ei in E]) #+end_src Les paramètres de variance sont estimés en logarithme, ce qui supprime la contrainte de positivité. Les intervalles de confiance sont construits pour le logarithme puis transformés, ce qui les rend asymétriques. La courbure de la log-vraisemblance concentrée donne directement la précision de \(\hat\psi\)\nbsp{}: l'inverse de l'opposé de sa hessienne est égal au bloc correspondant de l'inverse de l'opposé de la hessienne de la log-vraisemblance complète (Patefield, /Biometrika/, 1985). Enfin, deux modèles emboîtés se comparent par le test du rapport de vraisemblance, \(\mathrm{LR} = 2(\log L_1 - \log L_0)\), dont la loi asymptotique est celle d'un $\chi^2$ à autant de degrés de liberté que de restrictions, pourvu que le modèle restreint ne place pas un paramètre au bord de l'espace des paramètres, comme une variance nulle. * Prévision :PROPERTIES: :CUSTOM_ID: prevision :END: #+BEGIN_proposition Pour $h \geq 1$, la loi de $\alpha_{n+h}$ sachant $Y_n$ est $\mathcal N(a_{n+h|n}, P_{n+h|n})$, où \begin{equation*} a_{n+h|n} = T a_{n+h-1|n} + c,\qquad P_{n+h|n} = T P_{n+h-1|n} T' + RQR', \end{equation*} à partir de $a_{n|n}$ et $P_{n|n}$. La prévision de l'observation est \(\hat y_{n+h|n} = Z a_{n+h|n} + d\), de variance \(F_{n+h|n} = Z P_{n+h|n} Z' + H\), et, dans le cas scalaire, un intervalle de prévision de niveau $1 - \delta$ est \(\hat y_{n+h|n} \pm z_{1-\delta/2}\sqrt{F_{n+h|n}}\), où $z_{1-\delta/2}$ est un quantile de la loi normale centrée réduite. #+END_proposition #+BEGIN_proof Aucune observation n'est disponible après la date \(n\)\nbsp{}: la loi de $\alpha_{n+h}$ sachant $Y_n$ s'obtient en appliquant $h$ fois l'étape de prédiction du filtre, sans mise à jour, et la loi de $y_{n+h}$ s'en déduit par l'équation de mesure. #+END_proof Autrement dit, prévoir revient à filtrer une série complétée par des observations manquantes aux dates $n+1, \dots, n+h$. Avec des matrices constantes, on obtient \(a_{n+h|n} = T^h a_{n|n} + \sum_{j=0}^{h-1}T^jc\) et \begin{equation*} P_{n+h|n} = T^h P_{n|n} (T')^h + \sum_{j=0}^{h-1} T^j RQR' (T')^j. \end{equation*} #+BEGIN_exemple Dans le modèle de tendance lisse, \(T^h = \begin{pmatrix} 1 & h\\ 0 & 1 \end{pmatrix}\) et \(ZT^jR = j\). La prévision prolonge linéairement la tendance filtrée, \(\hat y_{n+h|n} = a_{\mu, n|n} + h\,a_{\beta, n|n}\), où $a_{\mu, n|n}$ et $a_{\beta, n|n}$ sont les composantes de $a_{n|n}$. Comme \(\mu_{n+h} = \mu_n + h\beta_n + \sum_{j=1}^{h-1} j\,\zeta_{n+h-j}\), sa variance est \begin{equation*} F_{n+h|n} = \sigma_\varepsilon^2 + \begin{pmatrix} 1 & h \end{pmatrix} P_{n|n} \begin{pmatrix} 1\\ h \end{pmatrix} + \sigma_\zeta^2\sum_{j=1}^{h-1} j^2. \end{equation*} Le dernier terme, égal à $\sigma_\zeta^2(h-1)h(2h-1)/6$, croît comme \(\sigma_\zeta^2h^3/3\)\nbsp{}: les intervalles de prévision d'une tendance intégrée d'ordre deux s'élargissent comme $h^{3/2}$. #+END_exemple #+begin_src python :session kalman :exports code :results none def previsions(a, P, Z, T, R, H, Q, h): RQR = R @ Q @ R.T y_prev, F_prev = np.zeros(h), np.zeros(h) for j in range(h): a = T @ a P = T @ P @ T.T + RQR y_prev[j], F_prev[j] = (Z @ a)[0], (Z @ P @ Z.T + H)[0, 0] return y_prev, F_prev #+end_src * Le filtre de Hodrick-Prescott, un lisseur de Kalman :PROPERTIES: :CUSTOM_ID: application :END: Le filtre de Hodrick et Prescott (/Journal of Money, Credit and Banking/, 1997, d'après un document de travail de 1980) est l'outil le plus répandu pour séparer la tendance et le cycle d'une série macroéconomique. On montre qu'il coïncide avec le lisseur de Kalman d'un modèle de tendance lisse, ce qui permet d'estimer son paramètre par le maximum de vraisemblance, puis on applique le résultat au PIB par tête français. ** Le filtre de Hodrick-Prescott :PROPERTIES: :CUSTOM_ID: filtre-hp :END: #+BEGIN_definition Pour une série $y_1, \dots, y_n$ et un paramètre $\lambda > 0$, la tendance de Hodrick-Prescott est la suite $\hat\mu_1, \dots, \hat\mu_n$ qui minimise \begin{equation*} S(\mu) = \sum_{t=1}^n (y_t - \mu_t)^2 + \lambda\sum_{t=3}^n \left(\Delta^2\mu_t\right)^2, \qquad \Delta^2\mu_t = \mu_t - 2\mu_{t-1} + \mu_{t-2}. \end{equation*} Le cycle est l'écart $y_t - \hat\mu_t$. #+END_definition Le critère arbitre entre l'ajustement aux données et la régularité de la tendance, mesurée par ses différences secondes. Pour $\lambda = 0$, la tendance est la série elle-même\nbsp{}; quand $\lambda$ tend vers l'infini, elle tend vers une droite (voir l'[[ex-limites-hp][exercice]]). #+BEGIN_property La tendance de Hodrick-Prescott est l'unique solution du système linéaire \((I_n + \lambda D'D)\hat\mu = y\), où $D$ est la matrice de taille $(n-2)\times n$ dont la ligne $t$ contient les coefficients $1$, $-2$ et $1$ dans les colonnes $t$, $t+1$ et $t+2$, et des zéros ailleurs. #+END_property #+BEGIN_proof Le critère s'écrit \(S(\mu) = (y - \mu)'(y - \mu) + \lambda\mu'D'D\mu\). C'est une fonction quadratique de hessienne $2(I_n + \lambda D'D)$, définie positive puisque $D'D$ est semi-définie positive\nbsp{}: le critère est strictement convexe, et son unique minimum annule le gradient \(-2(y - \mu) + 2\lambda D'D\mu\). #+END_proof La matrice $I_n + \lambda D'D$ est pentadiagonale\nbsp{}: le système se résout avec un solveur pour matrices creuses, en un nombre d'opérations proportionnel à $n$. #+begin_src python :session kalman :exports code :results none def filtre_hp(y, lam): n = len(y) D = sparse.diags([1.0, -2.0, 1.0], [0, 1, 2], shape=(n-2, n)) return spsolve((sparse.eye(n) + lam*D.T @ D).tocsc(), y) #+end_src #+BEGIN_remarque Appliqué à une série infinie, le filtre est une moyenne mobile symétrique dont le gain vaut \(1/(1 + 16\lambda\sin^4(\omega/2))\) pour la tendance, à la fréquence $\omega$ (King et Rebelo, /Journal of Economic Dynamics and Control/, 1993). Ce gain vaut un demi pour les cycles de période $2\pi/\omega$ telle que \(16\lambda\sin^4(\omega/2) = 1\)\nbsp{}: les fluctuations plus courtes sont attribuées au cycle, les plus longues à la tendance. La valeur usuelle $\lambda = 1\,600$ en données trimestrielles place cette période à une quarantaine de trimestres, soit une dizaine d'années. En données annuelles, $\lambda = 100$, retenu par Backus et Kehoe (/American Economic Review/, 1992), la place à une vingtaine d'années, et $\lambda = 6{,}25$, préconisé par Ravn et Uhlig (/Review of Economics and Statistics/, 2002) pour retrouver le filtre trimestriel usuel, à une dizaine d'années. #+END_remarque ** Le modèle de tendance lisse :PROPERTIES: :CUSTOM_ID: tendance-lisse :END: #+BEGIN_theorem Considérons le modèle de tendance lisse \begin{equation*} y_t = \mu_t + \varepsilon_t,\qquad \mu_t = \mu_{t-1} + \beta_{t-1},\qquad \beta_t = \beta_{t-1} + \zeta_t, \end{equation*} avec $\varepsilon_t \sim \mathcal N(0, \sigma_\varepsilon^2)$, $\zeta_t \sim \mathcal N(0, \sigma_\zeta^2)$ et une loi a priori diffuse sur le niveau et la pente initiaux. La tendance lissée $\mathbb E[\mu_t \mid Y_n]$ est la tendance de Hodrick-Prescott de paramètre \(\lambda = \sigma_\varepsilon^2/\sigma_\zeta^2\). #+END_theorem #+BEGIN_proof Les équations du modèle donnent, pour $t \geq 3$, \begin{equation*} \Delta^2\mu_t = (\mu_t - \mu_{t-1}) - (\mu_{t-1} - \mu_{t-2}) = \beta_{t-1} - \beta_{t-2} = \zeta_{t-1}. \end{equation*} La tendance $(\mu_1, \dots, \mu_n)$ est donc l'image de $(\mu_1, \beta_1, \zeta_2, \dots, \zeta_{n-1})$ par l'application linéaire définie par $\mu_2 = \mu_1 + \beta_1$ et \(\mu_t = 2\mu_{t-1} - \mu_{t-2} + \zeta_{t-1}\) pour $t \geq 3$. Cette application est bijective, de matrice triangulaire à diagonale unité, et son jacobien vaut un. Avec une densité a priori constante pour $(\mu_1, \beta_1)$, limite d'une loi normale dont la variance tend vers l'infini, et des $\zeta_t$ indépendants de loi $\mathcal N(0, \sigma_\zeta^2)$, la densité a priori de la tendance est \begin{equation*} p(\mu_1, \dots, \mu_n) \propto \exp\left(-\frac{1}{2\sigma_\zeta^2}\sum_{t=3}^n\left(\Delta^2\mu_t\right)^2\right). \end{equation*} Sachant la tendance, les observations sont indépendantes, de loi $\mathcal N(\mu_t, \sigma_\varepsilon^2)$. Par la formule de Bayes, la densité a posteriori de la tendance est proportionnelle au produit de la vraisemblance et de la densité a priori\nbsp{}: \begin{equation*} p(\mu_1, \dots, \mu_n \mid Y_n) \propto \exp\left(-\frac{1}{2\sigma_\varepsilon^2}\left[\sum_{t=1}^n(y_t - \mu_t)^2 + \lambda\sum_{t=3}^n\left(\Delta^2\mu_t\right)^2\right]\right). \end{equation*} C'est la densité d'une loi normale. Son espérance est égale à son mode, qui minimise le crochet, c'est-à-dire à la tendance de Hodrick-Prescott. Or le lisseur de Kalman, avec l'initialisation diffuse, calcule précisément l'espérance a posteriori $\mathbb E[\mu_t \mid Y_n]$. La pente $\beta_n$, qui n'intervient pas dans les observations, ne joue aucun rôle. #+END_proof Ce résultat prolonge l'interprétation bayésienne des splines de lissage (Wahba, /Journal of the Royal Statistical Society B/, 1978). Harvey et Jaeger (/Journal of Applied Econometrics/, 1993) en ont tiré les conséquences pour l'analyse du cycle\nbsp{}: la tendance de Hodrick-Prescott ne dépend que du rapport des deux variances, et le filtre est optimal si la série est engendrée par le modèle de tendance lisse avec \(\sigma_\varepsilon^2/\sigma_\zeta^2 = \lambda\). Le modèle apporte en retour ce que le filtre ne donne pas\nbsp{}: des bandes de confiance autour de la tendance, une tendance unilatérale, calculée par le filtre, qui n'utilise que le passé, des prévisions et surtout une vraisemblance, qui permet d'estimer $\lambda$ au lieu de le fixer. #+BEGIN_remarque La tendance lissée n'est pas une propriété de la loi des observations, mais de la décomposition retenue. Le modèle de tendance lisse suppose indépendants les chocs de la tendance et ceux de l'écart à la tendance\nbsp{}; d'autres hypothèses sont compatibles avec la même loi de $y_t$ et donnent d'autres tendances. À l'opposé, la décomposition de Beveridge et Nelson (/Journal of Monetary Economics/, 1981) définit la tendance comme la prévision de long terme de la série, corrigée de la croissance tendancielle, ce qui revient à supposer parfaitement corrélés les chocs de la tendance et ceux du cycle\nbsp{}: la tendance est alors une marche aléatoire. Morley, Nelson et Zivot (/Review of Economics and Statistics/, 2003) rappellent que, sur le PIB américain, cette tendance absorbe l'essentiel des fluctuations, et montrent que le modèle de tendance et de cycle de Clark, estimé sans imposer l'indépendance des chocs, donne des estimations filtrées de la tendance et du cycle identiques à celles de Beveridge et Nelson. Sur le PIB trimestriel américain de 1947 à 1998, la corrélation estimée entre les chocs vaut $-0{,}9$, et l'hypothèse d'indépendance est rejetée au seuil de 5\nbsp{}%, de justesse. Pour une marche aléatoire avec dérive, qui s'impose [[#tendance-lineaire-locale][plus bas]] pour le PIB par tête français sur longue période, la tendance de Beveridge et Nelson est la série elle-même et le cycle est nul. La tendance de Hodrick-Prescott n'est donc qu'une décomposition parmi d'autres, fixée par deux hypothèses\nbsp{}: l'indépendance des composantes et la forme de la tendance, dont $\lambda$ règle la régularité. #+END_remarque ** Les données :PROPERTIES: :CUSTOM_ID: donnees :END: On utilise le PIB par tête de la France de la base du projet Maddison, dans sa version 2020, téléchargée comme dans la note sur la [[https://stephane-adjemian.fr/posts/representer-graphiquement-une-serie-temporelle-du-pib/][représentation graphique d'une série temporelle du PIB]]. La série annuelle est continue de 1820 à 2018, soit $n = 199$ observations. On travaille sur \(y_t = 100\log(\text{PIB par tête})\), de sorte que les différences premières s'interprètent comme des taux de croissance en pourcentage et les écarts-types en points de pourcentage. #+begin_src python :session kalman :exports code :results none MADDISON = 'mpd2020' if not os.path.exists(MADDISON+'.xlsx'): url.urlretrieve('https://www.rug.nl/ggdc/historicaldevelopment/maddison/data/'+MADDISON+'.xlsx', MADDISON+'.xlsx') data = pd.read_excel(MADDISON+'.xlsx', 'Full data') france = data[(data.countrycode == 'FRA') & (data.year >= 1820)] annees = france.year.values.astype(int) y = 100*np.log(france.gdppc.values) dy = np.diff(y) for debut, fin in ((1820, 2018), (1820, 1913), (1950, 1973), (1974, 2018)): print(debut, fin, (y[annees == fin] - y[annees == debut])/(fin - debut)) print(annees[1:][np.argsort(dy)[:2]], np.sort(dy)[:2], annees[1:][np.argmax(dy)], dy.max()) #+end_src La croissance annuelle moyenne est de $1{,}54$ point sur l'ensemble de la période\nbsp{}: $1{,}21$ point par an entre 1820 et 1913, $3{,}94$ entre 1950 et 1973 et $1{,}39$ depuis 1974. Les deux guerres mondiales laissent des chutes considérables, de $21{,}8$ points en 1918 et de $20{,}0$ points en 1941, suivies de rattrapages de grande ampleur, jusqu'à $40{,}4$ points en 1946. Ces années exceptionnelles pèsent sur tous les résultats qui suivent. ** Vérification numérique :PROPERTIES: :CUSTOM_ID: verification :END: On compare la tendance de Hodrick-Prescott, avec $\lambda = 100$, et la tendance lissée du modèle avec $\sigma_\varepsilon^2 = 1$ et $\sigma_\zeta^2 = 1/100$, pour plusieurs valeurs de \(\kappa\)\nbsp{}: #+begin_src python :session kalman :exports code :results none lam = 100 tendance_hp = filtre_hp(y, lam) def lisse_tendance(y, s2_eps, s2_zeta, kappa): Z, T, R, H, Q = tendance_lisse(s2_eps, s2_zeta) res = filtre_kalman(y, Z, T, R, H, Q, np.zeros(2), kappa*np.eye(2)) return res, lisseur_kalman(res, T) for kap in (1e3, 1e5, 1e7, 1e9, 1e11): _, (a_l, _) = lisse_tendance(y, 1.0, 1/lam, kap) print(kap, np.max(np.abs(tendance_hp - a_l[:, 0]))) kappa = 1e9 #+end_src | $\kappa$ | Écart maximal | |-----------+-----------------------| | $10^3$ | $3{,}3\times 10^{-1}$ | | $10^5$ | $3{,}3\times 10^{-3}$ | | $10^7$ | $3{,}3\times 10^{-5}$ | | $10^9$ | $3{,}2\times 10^{-7}$ | | $10^{11}$ | $2{,}2\times 10^{-5}$ | L'écart décroît comme $1/\kappa$ tant que l'approximation diffuse domine, puis remonte lorsque les erreurs d'arrondi l'emportent\nbsp{}: avec $\kappa = 10^{11}$, le calcul des premières variances filtrées perd une dizaine de chiffres significatifs. Il est maximal en début d'échantillon, là où l'initialisation compte, comme le montre la figure [[fig:pib-france][ci-dessous]]. On retient désormais $\kappa = 10^9$. #+begin_src python :session kalman :exports none :results none res_hp, (a_hp, P_hp) = lisse_tendance(y, 1.0, 1/lam, kappa) fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(annees, y, 'k', linewidth=0.8, label=r'$y_t$') axes[0].plot(annees, tendance_hp, 'b', linewidth=1.5, label='Hodrick-Prescott') axes[0].plot(annees, a_hp[:, 0], 'r--', linewidth=1.5, label='lisseur de Kalman') axes[0].set_xlabel('année') axes[0].legend() axes[1].plot(annees, 1e7*(tendance_hp - a_hp[:, 0]), 'b', linewidth=1) axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xlabel('année') axes[1].set_ylabel(r'écart ($\times 10^{-7}$)') fig.tight_layout() fig.savefig("kalman-pib-france.svg", transparent=True) #+end_src #+CAPTION: *À gauche, logarithme du PIB par tête de la France (multiplié par $100$), tendance de Hodrick-Prescott avec $\lambda = 100$ et tendance lissée du modèle de tendance lisse avec $\kappa = 10^9$. À droite, écart entre les deux tendances.* #+LABEL: fig:pib-france [[file:kalman-pib-france.svg]] Le contrôle externe utilise la classe =UnobservedComponents= de =statsmodels=, qui met en œuvre l'initialisation diffuse exacte. On compare les tendances lissées et les log-vraisemblances pour trois couples de variances\nbsp{}: #+begin_src python :session kalman :exports code :results none from statsmodels.tsa.statespace.structural import UnobservedComponents modele_sm = UnobservedComponents(y, level='smooth trend', use_exact_diffuse=True) for s2e, s2z in ((1.0, 0.01), (10.0, 5.0), (40.0, 0.4)): res, (a_l, _) = lisse_tendance(y, s2e, s2z, kappa) tendance_sm = modele_sm.smooth([s2e, s2z]).smoothed_state[0] print(np.max(np.abs(tendance_sm - a_l[:, 0])), modele_sm.loglike([s2e, s2z]) - log_vraisemblance(res, d=2)) #+end_src Les tendances diffèrent de moins de $1{,}4\times 10^{-5}$, et la différence des log-vraisemblances vaut $-1{,}83787$ à $2\times 10^{-5}$ près pour les trois couples, soit \(-\log 2\pi\)\nbsp{}: comme annoncé, la vraisemblance diffuse et la vraisemblance diffuse exacte ne diffèrent que par une constante, qui n'affecte ni les estimations ni les tests. ** Estimer le paramètre de lissage :PROPERTIES: :CUSTOM_ID: estimer-lambda :END: Le paramètre $\lambda$ est l'inverse du rapport signal sur bruit \(q = \sigma_\zeta^2/\sigma_\varepsilon^2\). On concentre la vraisemblance par rapport à $\sigma_\varepsilon^2$ et on la maximise en $\log q$, en écartant les $d = 2$ premières innovations, puisque le niveau et la pente initiaux sont diffus. On calcule aussi la vraisemblance avec $\lambda = 100$, et l'estimation sur deux sous-périodes. #+begin_src python :session kalman :exports code :results none def logLc_tendance_lisse(log_q, y): Z, T, R, H, Q = tendance_lisse(1.0, np.exp(log_q)) res = filtre_kalman(y, Z, T, R, H, Q, np.zeros(2), kappa*np.eye(2)) return vraisemblance_concentree(res, d=2) def estime_lambda(y): opt = minimize_scalar(lambda x: -logLc_tendance_lisse(x, y)[0], bounds=(np.log(1e-6), np.log(1e3)), method='bounded', options={'xatol': 1e-8}) return opt.x log_q = estime_lambda(y) logL_max, s2_eps = logLc_tendance_lisse(log_q, y) lam_hat = np.exp(-log_q) se = 1/np.sqrt(-hessienne(lambda x: logLc_tendance_lisse(x[0], y)[0], [log_q])[0, 0]) ic = np.exp(-log_q + np.array([-1.96, 1.96])*se) logL_100, s2_eps_100 = logLc_tendance_lisse(np.log(1/100), y) LR = 2*(logL_max - logL_100) print(lam_hat, se, ic, LR, chi2.sf(LR, 1)) print(2*np.pi/(2*np.arcsin((16*lam_hat)**-0.25))) for debut in (1870, 1950): print(debut, np.exp(-estime_lambda(y[annees >= debut]))) #+end_src L'estimation donne $\hat\lambda = 1{,}24$, avec un intervalle de confiance à 95\nbsp{}% de $[0{,}65\,;\,2{,}36]$, construit à partir de l'écart-type de $\log\hat q$, qui vaut $0{,}33$. On est très loin des valeurs usuelles\nbsp{}: le test du rapport de vraisemblance rejette $\lambda = 100$ avec une statistique de $93{,}8$, pour une valeur critique de $3{,}84$ au seuil de 5\nbsp{}%. D'après la remarque sur la réponse en fréquence, le gain de la tendance vaut un demi pour une période de $6{,}4$ ans avec $\hat\lambda$, contre une vingtaine d'années avec \(\lambda = 100\)\nbsp{}: la tendance estimée absorbe l'essentiel des fluctuations de moyen terme. Le résultat n'est pas dû aux seules guerres\nbsp{}: l'estimation vaut $0{,}86$ à partir de 1870 et $0{,}53$ à partir de 1950. La figure [[fig:vraisemblance][ci-dessous]] montre la log-vraisemblance concentrée en fonction de \(\lambda\)\nbsp{}: $\lambda = 6{,}25$ est déjà nettement moins vraisemblable que $\hat\lambda$, et $\lambda = 100$ ou $\lambda = 1\,600$ le sont beaucoup moins encore. Pour comprendre ce rejet, on compare les deux modèles, avec les variances estimées, à l'aide des innovations standardisées et du cycle \(y_t - a_{\mu, t|n}\)\nbsp{}: #+begin_src python :session kalman :exports code :results none def ajuste(y, s2_eps, lam): res, (a_l, P_l) = lisse_tendance(y, s2_eps, s2_eps/lam, kappa) e = res['v'][2:, 0]/np.sqrt(res['F'][2:, 0, 0]) return res, a_l, P_l, e, y - a_l[:, 0] resultats = {'100': ajuste(y, s2_eps_100, 100), 'hat': ajuste(y, s2_eps, lam_hat)} for nom, (res, a_l, P_l, e, cycle) in resultats.items(): print(nom, acf(e, 3), cycle.std(), acf(cycle, 1)) #+end_src | | $\lambda = 100$ | $\hat\lambda = 1{,}24$ | |----------------------------------------+-----------------+------------------------| | $\hat\sigma_\varepsilon$ | $6{,}85$ | $3{,}40$ | | $\hat\sigma_\zeta$ | $0{,}68$ | $3{,}06$ | | Log-vraisemblance | $-704{,}4$ | $-657{,}5$ | | Autocorrélation des innovations (1) | $0{,}66$ | $0{,}08$ | | Autocorrélation des innovations (2) | $0{,}34$ | $-0{,}26$ | | Écart-type du cycle | $5{,}94$ | $2{,}70$ | | Autocorrélation du cycle (1) | $0{,}57$ | $-0{,}22$ | #+begin_src python :session kalman :exports none :results none lam_grille = np.logspace(-2, 4, 121) profil = [logLc_tendance_lisse(-np.log(l), y)[0] for l in lam_grille] fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(lam_grille, profil, 'b', linewidth=1) for l, c, etiquette in ((lam_hat, 'r', r'$\hat\lambda$'), (6.25, 'g', r'$\lambda = 6{,}25$'), (100, 'k', r'$\lambda = 100$')): axes[0].axvline(l, color=c, linestyle='--', linewidth=0.8, label=etiquette) axes[0].set_xscale('log') axes[0].set_xlabel(r'$\lambda$') axes[0].set_ylabel('log-vraisemblance concentrée') axes[0].legend() k = np.arange(1, 11) axes[1].bar(k - 0.17, acf(resultats['100'][3], 10), width=0.34, color='k', label=r'$\lambda = 100$') axes[1].bar(k + 0.17, acf(resultats['hat'][3], 10), width=0.34, color='r', label=r'$\hat\lambda$') bande = 1.96/np.sqrt(len(resultats['hat'][3])) for s in (-1, 1): axes[1].axhline(s*bande, color='k', linestyle='--', linewidth=0.8) axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xticks(k) axes[1].set_xlabel('retard') axes[1].set_ylabel('autocorrélation des innovations') axes[1].legend() fig.tight_layout() fig.savefig("kalman-vraisemblance.svg", transparent=True) #+end_src #+CAPTION: *À gauche, log-vraisemblance concentrée du modèle de tendance lisse en fonction de $\lambda$ (échelle logarithmique). À droite, autocorrélations des innovations standardisées pour $\lambda = 100$ et pour $\hat\lambda$, avec la bande $\pm 1{,}96/\sqrt{n-2}$.* #+LABEL: fig:vraisemblance [[file:kalman-vraisemblance.svg]] Les deux valeurs de $\lambda$ racontent des histoires très différentes (figure [[fig:cycles][ci-dessous]]). Avec $\lambda = 100$, la tendance est régulière et le cycle, d'écart-type $5{,}9$ points, est très persistant\nbsp{}: il enregistre les guerres comme des récessions de plusieurs années. Mais le modèle suppose que l'écart à la tendance, $\varepsilon_t$, est un bruit blanc, et ses innovations standardisées ont une autocorrélation de $0{,}66$ à l'ordre un\nbsp{}: la spécification est rejetée par ses propres diagnostics. Le maximum de vraisemblance lève la contradiction en rendant la tendance flexible. Avec $\hat\lambda$, la tendance absorbe les fluctuations persistantes et le cycle résiduel, d'écart-type $2{,}7$ points, n'a plus de persistance. Le modèle de tendance lisse n'a pas de place pour un cycle persistant\nbsp{}: il ne connaît que la tendance et le bruit. Fixer $\lambda$, c'est donc choisir une définition du cycle, pas l'estimer, conclusion à laquelle arrivaient déjà Harvey et Jaeger (1993). #+begin_src python :session kalman :exports none :results none fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(annees, y, 'k', linewidth=0.8, label=r'$y_t$') axes[0].plot(annees, resultats['100'][1][:, 0], 'b', linewidth=1.2, label=r'tendance, $\lambda = 100$') axes[0].plot(annees, resultats['hat'][1][:, 0], 'r', linewidth=1.2, label=r'tendance, $\hat\lambda$') axes[0].set_xlabel('année') axes[0].legend() axes[1].plot(annees, resultats['100'][4], 'b', linewidth=1, label=r'$\lambda = 100$') axes[1].plot(annees, resultats['hat'][4], 'r', linewidth=1, label=r'$\hat\lambda$') axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xlabel('année') axes[1].set_ylabel(r'$y_t - a_{\mu, t|n}$') axes[1].legend() fig.tight_layout() fig.savefig("kalman-cycles.svg", transparent=True) #+end_src #+CAPTION: *Tendances lissées (à gauche) et cycles (à droite) pour $\lambda = 100$ et pour $\hat\lambda$.* #+LABEL: fig:cycles [[file:kalman-cycles.svg]] *** Libérer la variance du niveau :PROPERTIES: :CUSTOM_ID: tendance-lineaire-locale :END: Le modèle de tendance lisse impose $\sigma_\eta^2 = 0$. Le modèle de tendance linéaire locale, qui estime les trois variances, tranche autrement. On concentre la vraisemblance par rapport à $\sigma_\eta^2$, les rapports des deux autres variances à $\sigma_\eta^2$ étant estimés en logarithme et bornés inférieurement par $e^{-20}$. #+begin_src python :session kalman :exports code :results none def logLc_tll(x, y): Z, T, R, H, Q = tendance_lineaire_locale(np.exp(x[0]), 1.0, np.exp(x[1])) res = filtre_kalman(y, Z, T, R, H, Q, np.zeros(2), kappa*np.eye(2)) return vraisemblance_concentree(res, d=2) opt_tll = minimize(lambda x: -logLc_tll(x, y)[0], [0.0, -2.0], method='L-BFGS-B', bounds=[(-20.0, 5.0)]*2) logL_tll, s2_eta = logLc_tll(opt_tll.x, y) print(opt_tll.x, s2_eta, logL_tll, 2*(logL_tll - logL_max)) #+end_src L'optimum est atteint au bord\nbsp{}: les deux rapports sont à leur borne inférieure ou presque, et $\hat\sigma_\eta = 5{,}99$. Le modèle se réduit à une marche aléatoire avec dérive, $\Delta y_t = \beta + \eta_t$, dont la pente constante est la croissance moyenne, $1{,}54$ point par an, et dont les chocs ont l'écart-type de la croissance annuelle. La log-vraisemblance, $-635{,}0$, dépasse de $22{,}6$ celle du modèle de tendance lisse. La statistique du rapport de vraisemblance, $45{,}1$, ne suit pas une loi du $\chi^2$, puisque l'hypothèse $\sigma_\eta^2 = 0$ place un paramètre au bord de l'espace des paramètres. Dans le cadre d'observations indépendantes étudié par Self et Liang (/Journal of the American Statistical Association/, 1987), sa loi asymptotique serait un mélange à parts égales d'une masse en zéro et d'une loi \(\chi^2(1)\)\nbsp{}; pour une variance d'état dans un modèle de séries temporelles, elle peut être différente. Avec une statistique de cette ampleur, la conclusion ne fait cependant aucun doute. La marche aléatoire avec dérive, qui n'a qu'un paramètre de variance, est bien plus vraisemblable que le modèle de tendance lisse, qui en a deux\nbsp{}: chaque variation annuelle du PIB par tête y est un choc permanent sur le niveau, y compris les chutes et les rattrapages des guerres. #+BEGIN_remarque On retrouve le phénomène d'accumulation à la frontière signalé dans la note sur le [[https://stephane-adjemian.fr/posts/biais-de-l-estimateur-mco-d-un-processus-ar1/#etat-mesure][biais de l'estimateur des moindres carrés d'un AR(1)]]\nbsp{}: dans les modèles à composantes inobservées, les variances estimées sont exactement nulles avec une probabilité positive. Surtout, si la série est une marche aléatoire, le filtre de Hodrick-Prescott fabrique un cycle persistant qu'elle ne contient pas (Cogley et Nason, /Journal of Economic Dynamics and Control/, 1995)\nbsp{}: le cycle obtenu avec $\lambda = 100$ relève en partie de cet artefact. #+END_remarque ** Tendance filtrée et tendance lissée :PROPERTIES: :CUSTOM_ID: filtre-vs-lisseur :END: La tendance filtrée $a_{\mu, t|t}$ n'utilise que les observations passées\nbsp{}: c'est la version unilatérale, en temps réel, du filtre de Hodrick-Prescott (Stock et Watson, /Journal of Monetary Economics/, 1999). Son gain rejoint rapidement sa valeur stationnaire, que l'on calcule par l'équation de Riccati algébrique\nbsp{}: #+begin_src python :session kalman :exports code :results none for nom, l in (('100', 100), ('hat', lam_hat)): Z, T, R, H, Q = tendance_lisse(1.0, 1/l) P_bar = solve_discrete_are(T.T, Z.T, R @ Q @ R.T, H) K_bar = P_bar @ Z.T/(Z @ P_bar @ Z.T + H) K_t = resultats[nom][0]['K'][:, :, 0] print(nom, K_bar.ravel(), annees[np.argmax(np.all(np.abs(K_t - K_bar.ravel()) < 1e-3, axis=1))]) res, a_l, P_l, e, cycle = resultats['100'] revision = res['a_filt'][:, 0] - a_l[:, 0] print(annees[np.argmax(np.abs(revision))], revision.min()) print(np.sqrt(res['P_filt'][annees == 1930, 0, 0]), np.sqrt(P_l[annees == 1930, 0, 0])) print(acf(y - res['a_filt'][:, 0], 1), acf(y - a_l[:, 0], 1)) #+end_src Avec $\lambda = 100$, le gain stationnaire vaut $(0{,}362\,;\,0{,}080)'$, atteint à $10^{-3}$ près dès 1834\nbsp{}: chaque année, la tendance filtrée corrige son niveau de 36\nbsp{}% de l'innovation et sa pente de 8\nbsp{}%. Avec $\hat\lambda$, il vaut $(0{,}750\,;\,0{,}450)'$, atteint dès 1825. La figure [[fig:filtre-vs-lisseur][ci-dessous]] compare les deux tendances pour $\lambda = 100$ autour des deux guerres. En temps réel, les effondrements sont en partie attribués à la tendance, qui décroche\nbsp{}; avec le recul, le lisseur, qui voit la reconstruction, les attribue au cycle. En 1945, la tendance filtrée est inférieure de $31{,}5$ points à la tendance lissée. L'écart-type conditionnel de la tendance est de $4{,}1$ points pour le filtre et de $2{,}3$ points pour le lisseur, loin des extrémités de l'échantillon. Le cycle unilatéral est plus persistant que le cycle bilatéral, avec une autocorrélation d'ordre un de $0{,}66$ contre $0{,}57$. #+begin_src python :session kalman :exports none :results none res, a_l, P_l, e, cycle = resultats['100'] fenetre = (annees >= 1900) & (annees <= 1960) af, sf = res['a_filt'][:, 0], np.sqrt(res['P_filt'][:, 0, 0]) al, sl = a_l[:, 0], np.sqrt(P_l[:, 0, 0]) fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(annees[fenetre], y[fenetre], 'k', linewidth=0.8, label=r'$y_t$') axes[0].plot(annees[fenetre], af[fenetre], 'b', linewidth=1.2, label=r'tendance filtrée $a_{\mu, t|t}$') axes[0].fill_between(annees[fenetre], (af-2*sf)[fenetre], (af+2*sf)[fenetre], color='b', alpha=0.12, linewidth=0) axes[0].plot(annees[fenetre], al[fenetre], 'r', linewidth=1.2, label=r'tendance lissée $a_{\mu, t|n}$') axes[0].fill_between(annees[fenetre], (al-2*sl)[fenetre], (al+2*sl)[fenetre], color='r', alpha=0.2, linewidth=0) axes[0].set_xlabel('année') axes[0].legend(loc='upper left') axes[1].plot(annees, y - af, 'b', linewidth=1, label='cycle unilatéral') axes[1].plot(annees, y - al, 'r', linewidth=1, label='cycle bilatéral') axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xlabel('année') axes[1].legend() fig.tight_layout() fig.savefig("kalman-filtre-vs-lisseur.svg", transparent=True) #+end_src #+CAPTION: *Modèle de tendance lisse avec $\lambda = 100$. À gauche, tendances filtrée et lissée de 1900 à 1960, avec des bandes de plus ou moins deux écarts-types conditionnels. À droite, cycles unilatéral, $y_t - a_{\mu, t|t}$, et bilatéral, $y_t - a_{\mu, t|n}$, qui est le cycle de Hodrick-Prescott.* #+LABEL: fig:filtre-vs-lisseur [[file:kalman-filtre-vs-lisseur.svg]] #+BEGIN_remarque Le traitement des observations manquantes permet d'interpoler la tendance. Si l'on retire les années 1939 à 1945, le lisseur prolonge la tendance à travers la guerre\nbsp{}: il l'estime à $880{,}8$ points en 1942, avec un écart-type de $3{,}7$ points, contre $846{,}6$ observés et une tendance de $861{,}4$ avec toutes les données. #+END_remarque #+begin_src python :session kalman :exports code :results none y_manquant = y.copy() y_manquant[(annees >= 1939) & (annees <= 1945)] = np.nan _, (a_m, P_m) = lisse_tendance(y_manquant, s2_eps_100, s2_eps_100/100, kappa) print(a_m[annees == 1942, 0], np.sqrt(P_m[annees == 1942, 0, 0])) print(y[annees == 1942], resultats['100'][1][annees == 1942, 0]) #+end_src ** Une tendance et un cycle :PROPERTIES: :CUSTOM_ID: tendance-cycle :END: Pour obtenir un cycle persistant qui ne soit pas imposé par le choix de $\lambda$, il faut le modéliser. On remplace le bruit $\varepsilon_t$ par un processus autorégressif d'ordre deux stationnaire. C'est une variante du modèle de Clark (/Quarterly Journal of Economics/, 1987), dont la tendance comporte en outre un choc sur le niveau\nbsp{}: \begin{equation*} y_t = \mu_t + \psi_t,\qquad \mu_t = \mu_{t-1} + \beta_{t-1},\qquad \beta_t = \beta_{t-1} + \zeta_t,\qquad \psi_t = \phi_1\psi_{t-1} + \phi_2\psi_{t-2} + u_t, \end{equation*} avec \(u_t \sim \mathcal N(0, \sigma_u^2)\). L'état est \(\alpha_t = (\mu_t, \beta_t, \psi_t, \psi_{t-1})'\), la mesure est parfaite ($H = 0$) et \begin{equation*} Z = \begin{pmatrix} 1 & 0 & 1 & 0 \end{pmatrix},\quad T = \begin{pmatrix} 1 & 1 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & \phi_1 & \phi_2\\ 0 & 0 & 1 & 0 \end{pmatrix},\quad R = \begin{pmatrix} 0 & 0\\ 1 & 0\\ 0 & 1\\ 0 & 0 \end{pmatrix},\quad Q = \begin{pmatrix} \sigma_\zeta^2 & 0\\ 0 & \sigma_u^2 \end{pmatrix}. \end{equation*} L'initialisation est mixte\nbsp{}: diffuse pour la tendance, stationnaire, par l'équation de Lyapunov, pour le cycle. On concentre la vraisemblance par rapport à $\sigma_u^2$. Pour garantir la stationnarité du cycle, on paramètre $(\phi_1, \phi_2)$ par les autocorrélations partielles $r_1, r_2 \in \left]-1, 1\right[$, avec $\phi_2 = r_2$ et \(\phi_1 = r_1(1 - r_2)\) (Barndorff-Nielsen et Schou, /Journal of Multivariate Analysis/, 1973), elles-mêmes écrites \(r_i = \tanh(x_i)\) avec $x_i$ réel. #+begin_src python :session kalman :exports code :results none def tendance_cycle(s2_zeta, phi1, phi2, s2_u): Z = np.array([[1.0, 0.0, 1.0, 0.0]]) T = np.array([[1.0, 1.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, phi1, phi2], [0.0, 0.0, 1.0, 0.0]]) R = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [0.0, 0.0]]) return Z, T, R, np.zeros((1, 1)), np.diag([s2_zeta, s2_u]) def init_tendance_cycle(T, R, Q): P0 = np.zeros((4, 4)) P0[:2, :2] = kappa*np.eye(2) P0[2:, 2:] = solve_discrete_lyapunov(T[2:, 2:], (R @ Q @ R.T)[2:, 2:]) return np.zeros(4), P0 def parametres(x): r1, r2 = np.tanh(x[1]), np.tanh(x[2]) return np.exp(x[0]), r1*(1 - r2), r2 def logLc_tendance_cycle(x, y): Z, T, R, H, Q = tendance_cycle(*parametres(x), 1.0) res = filtre_kalman(y, Z, T, R, H, Q, *init_tendance_cycle(T, R, Q)) return vraisemblance_concentree(res, d=2) #+end_src Les guerres interdisent d'estimer ce modèle sur l'échantillon complet\nbsp{}: le cycle y absorbe les chutes et les rattrapages, sa racine autorégressive dominante vaut $0{,}95$ et la variance de la pente devient presque nulle, de sorte que le modèle se rapproche d'une marche aléatoire avec dérive. On l'estime donc sur la période 1950--2018, à partir de quatre points de départ, car la vraisemblance des modèles à composantes inobservées a souvent plusieurs maxima locaux. #+begin_src python :session kalman :exports code :results none y50, annees50 = y[annees >= 1950], annees[annees >= 1950] meilleur = None for x0 in ([-2.0, 0.5, 0.0], [-5.0, 1.0, -0.5], [0.0, 0.2, 0.2], [-1.0, 1.5, -0.8]): opt = minimize(lambda x: -logLc_tendance_cycle(x, y50)[0], x0, method='Nelder-Mead', options={'xatol': 1e-8, 'fatol': 1e-10, 'maxiter': 5000}) print(x0, -opt.fun) if meilleur is None or opt.fun < meilleur.fun: meilleur = opt logL_tc, s2_u = logLc_tendance_cycle(meilleur.x, y50) q_zeta, phi1, phi2 = parametres(meilleur.x) racines = np.roots([1, -phi1, -phi2]) print(q_zeta*s2_u, phi1, phi2, s2_u, np.abs(racines), 2*np.pi/np.abs(np.angle(racines[0]))) logL_st50 = logLc_tendance_lisse(estime_lambda(y50), y50)[0] print(logL_tc, logL_st50, chi2.sf(2*(logL_tc - logL_st50), 2)) #+end_src L'une des quatre optimisations s'arrête sur un maximum local où la première autocorrélation partielle du cycle tend vers un\nbsp{}; les trois autres convergent vers le même point. L'estimation donne $\hat\phi_1 = 0{,}807$ et \(\hat\phi_2 = -0{,}306\)\nbsp{}: les racines du polynôme autorégressif sont complexes, de module $0{,}55$, et le cycle a une période de $8{,}3$ ans. L'écart-type des chocs du cycle est de $1{,}03$ point, celui de la pente de la tendance de $0{,}40$ point. Le modèle améliore nettement la log-vraisemblance du modèle de tendance lisse estimé sur la même période, qui passe de $-126{,}4$ à \(-119{,}1\)\nbsp{}: la statistique du rapport de vraisemblance vaut $14{,}6$ pour les deux restrictions $\phi_1 = \phi_2 = 0$, soit une probabilité critique de $0{,}0007$. #+begin_src python :session kalman :exports code :results none Z_tc, T_tc, R_tc, H_tc, Q_tc = tendance_cycle(q_zeta*s2_u, phi1, phi2, s2_u) res_tc = filtre_kalman(y50, Z_tc, T_tc, R_tc, H_tc, Q_tc, *init_tendance_cycle(T_tc, R_tc, Q_tc)) a_tc, P_tc = lisseur_kalman(res_tc, T_tc) ecart_hp = lambda l: np.sqrt(np.mean((filtre_hp(y50, l) - a_tc[:, 0])**2)) opt = minimize_scalar(lambda x: ecart_hp(np.exp(x)), bounds=(np.log(0.1), np.log(1e4)), method='bounded') print(np.exp(opt.x), ecart_hp(np.exp(opt.x)), ecart_hp(100)) print(acf(res_tc['v'][2:, 0]/np.sqrt(res_tc['F'][2:, 0, 0]), 3)) print(a_tc[-1, 2], (y50 - filtre_hp(y50, 100))[-1]) #+end_src Les innovations standardisées ne présentent plus d'autocorrélation. La tendance du modèle est très proche d'une tendance de Hodrick-Prescott, mais pas de paramètre \(100\)\nbsp{}: la valeur de $\lambda$ qui la reproduit le mieux est $27$, avec un écart quadratique moyen de $0{,}10$ point, contre $0{,}39$ pour $\lambda = 100$. Le cycle lissé (figure [[fig:tendance-cycle][ci-dessous]]) retrouve les récessions de 1975, 1993 et 2009, et place l'économie légèrement au-dessus de sa tendance en 2018, de $0{,}8$ point contre $1{,}6$ pour le cycle de Hodrick-Prescott. #+begin_src python :session kalman :exports none :results none hp50 = filtre_hp(y50, 100) c, sc = a_tc[:, 2], np.sqrt(P_tc[:, 2, 2]) fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(annees50, y50, 'k', linewidth=0.8, label=r'$y_t$') axes[0].plot(annees50, a_tc[:, 0], 'r', linewidth=1.2, label='tendance du modèle') axes[0].plot(annees50, hp50, 'b--', linewidth=1.2, label=r'Hodrick-Prescott, $\lambda = 100$') axes[0].set_xlabel('année') axes[0].legend() axes[1].plot(annees50, c, 'r', linewidth=1.2, label=r'cycle $a_{\psi, t|n}$') axes[1].fill_between(annees50, c-2*sc, c+2*sc, color='r', alpha=0.2, linewidth=0) axes[1].plot(annees50, y50 - hp50, 'b--', linewidth=1, label=r'cycle HP, $\lambda = 100$') axes[1].axhline(0, color='k', linewidth=0.5) axes[1].set_xlabel('année') axes[1].legend() fig.tight_layout() fig.savefig("kalman-tendance-cycle.svg", transparent=True) #+end_src #+CAPTION: *Modèle de tendance et de cycle estimé sur 1950--2018. À gauche, tendance lissée et tendance de Hodrick-Prescott avec $\lambda = 100$. À droite, cycle lissé avec une bande de plus ou moins deux écarts-types conditionnels, et cycle de Hodrick-Prescott.* #+LABEL: fig:tendance-cycle [[file:kalman-tendance-cycle.svg]] ** Prévisions :PROPERTIES: :CUSTOM_ID: previsions-pib :END: On compare pour finir les prévisions de 2019 à 2028 de deux modèles estimés sur 1950--2018\nbsp{}: le modèle de tendance lisse avec $\lambda = 100$, la variance $\sigma_\varepsilon^2$ étant estimée, et le modèle de tendance et de cycle. #+begin_src python :session kalman :exports code :results none h = 10 s2_100_50 = logLc_tendance_lisse(np.log(1/100), y50)[1] modele_st = tendance_lisse(s2_100_50, s2_100_50/100) res_st = filtre_kalman(y50, *modele_st, np.zeros(2), kappa*np.eye(2)) prev = {'st': previsions(res_st['a_filt'][-1], res_st['P_filt'][-1], *modele_st, h), 'tc': previsions(res_tc['a_filt'][-1], res_tc['P_filt'][-1], Z_tc, T_tc, R_tc, H_tc, Q_tc, h)} for nom, (y_prev, F_prev) in prev.items(): print(nom, y_prev[0] - y50[-1], np.sqrt(F_prev[[0, 4, 9]])) print(res_st['a_filt'][-1][1], res_tc['a_filt'][-1][1], np.sqrt(s2_100_50/100), np.sqrt(q_zeta*s2_u)) #+end_src Avec $\lambda = 100$, la prévision pour 2019 est inférieure de $1{,}0$ point au niveau de 2018\nbsp{}: le cycle, supposé sans mémoire, disparaît immédiatement et la prévision repart de la tendance filtrée, qu'elle prolonge avec une pente de $0{,}60$ point par an. Le modèle avec cycle prévoit au contraire une croissance de $0{,}8$ point en 2019, puisque le cycle ne se résorbe que progressivement, puis une pente de $1{,}04$ point. Les écarts-types de prévision sont de $2{,}2$, $3{,}3$ et $5{,}6$ points à un, cinq et dix ans avec $\lambda = 100$, contre $1{,}4$, $4{,}9$ et $10{,}2$ points avec le cycle (figure [[fig:previsions][ci-dessous]]). La précision apparente du premier modèle à long terme tient à la faible variance qu'il impose à la pente de la tendance, $\sigma_\zeta = 0{,}17$ point contre \(0{,}40\)\nbsp{}: fixer $\lambda$, c'est aussi fixer l'incertitude sur la croissance future. #+begin_src python :session kalman :exports none :results none annees_prev = np.arange(annees50[-1] + 1, annees50[-1] + h + 1) fenetre = annees50 >= 1990 fig, axes = plt.subplots(1, 2, figsize=(12, 4), sharey=True) for ax, nom, titre in ((axes[0], 'st', r'tendance lisse, $\lambda = 100$'), (axes[1], 'tc', 'tendance et cycle AR(2)')): y_prev, F_prev = prev[nom] ax.plot(annees50[fenetre], y50[fenetre], 'k', linewidth=1) for z, alpha in ((1.645, 0.15), (0.674, 0.3)): ax.fill_between(annees_prev, y_prev - z*np.sqrt(F_prev), y_prev + z*np.sqrt(F_prev), color='b', alpha=alpha, linewidth=0) ax.plot(annees_prev, y_prev, 'b', linewidth=1.2) ax.set_title(titre) ax.set_xlabel('année') fig.tight_layout() fig.savefig("kalman-previsions.svg", transparent=True) #+end_src #+CAPTION: *Prévisions du logarithme du PIB par tête (multiplié par $100$) de 2019 à 2028, avec des intervalles de prévision à 50\nbsp{}% et 90\nbsp{}%, pour le modèle de tendance lisse avec $\lambda = 100$ (à gauche) et pour le modèle de tendance et de cycle (à droite), estimés sur 1950--2018.* #+LABEL: fig:previsions [[file:kalman-previsions.svg]] Au terme de l'application, le filtre de Hodrick-Prescott apparaît comme un cas particulier d'un modèle explicite, dont la vraisemblance juge les hypothèses. Sur le PIB par tête français, elle rejette la valeur usuelle du paramètre de lissage, préfère une marche aléatoire avec dérive au modèle de tendance lisse sur longue période, et, depuis 1950, retrouve un cycle de huit ans une fois celui-ci modélisé explicitement. * Exercices :PROPERTIES: :CUSTOM_ID: exercices :END: #+NAME: ex-ar2-mesure #+BEGIN_exercice On observe avec une erreur de mesure un processus autorégressif d'ordre deux stationnaire\nbsp{}: $y_t = x_t + \varepsilon_t$, avec \(x_t = \phi_1x_{t-1} + \phi_2x_{t-2} + \eta_t\), où $\varepsilon_t$ et $\eta_t$ sont des bruits blancs gaussiens indépendants, de variances $\sigma_\varepsilon^2$ et $\sigma_\eta^2$. Écrivez le modèle sous forme état-mesure et indiquez comment initialiser le filtre. Simulez $n = 200$ observations avec $\phi_1 = 1{,}2$, $\phi_2 = -0{,}5$ et $\sigma_\varepsilon = \sigma_\eta = 1$, puis comparez les erreurs quadratiques moyennes de $y_t$, de l'état filtré et de l'état lissé comme estimateurs de $x_t$. #+END_exercice #+ATTR_HTML: :class corrige #+BEGIN_details #+BEGIN_summary Corrigé #+END_summary L'état est $\alpha_t = (x_t, x_{t-1})'$, et \begin{equation*} Z = \begin{pmatrix} 1 & 0 \end{pmatrix},\quad T = \begin{pmatrix} \phi_1 & \phi_2\\ 1 & 0 \end{pmatrix},\quad R = \begin{pmatrix} 1\\ 0 \end{pmatrix},\quad H = \sigma_\varepsilon^2,\quad Q = \sigma_\eta^2. \end{equation*} Les racines du polynôme $1 - 1{,}2z + 0{,}5z^2$ sont de module \(\sqrt 2 > 1\)\nbsp{}: le processus est stationnaire, et l'on initialise le filtre par sa loi stationnaire, $a_0 = 0$ et $P_0$ solution de l'équation de Lyapunov. #+begin_src python :session kalman :exports code :results none phi_1, phi_2, n_ex = 1.2, -0.5, 200 x = np.zeros(n_ex + 100) for t in range(2, n_ex + 100): x[t] = phi_1*x[t-1] + phi_2*x[t-2] + rng.standard_normal() x = x[100:] y_ex = x + rng.standard_normal(n_ex) Z = np.array([[1.0, 0.0]]) T = np.array([[phi_1, phi_2], [1.0, 0.0]]) R = np.array([[1.0], [0.0]]) H, Q = np.eye(1), np.eye(1) P0 = solve_discrete_lyapunov(T, R @ Q @ R.T) res_ex = filtre_kalman(y_ex, Z, T, R, H, Q, np.zeros(2), P0) a_ex, _ = lisseur_kalman(res_ex, T) for estimateur in (y_ex, res_ex['a_filt'][:, 0], a_ex[:, 0]): print(np.sqrt(np.mean((estimateur - x)**2))) #+end_src Les erreurs quadratiques moyennes valent $1{,}03$ pour l'observation, $0{,}78$ pour l'état filtré et $0{,}72$ pour l'état lissé. La variance stationnaire de $x_t$ étant de $3{,}7$, le signal domine le bruit, et le gain à filtrer est moindre que dans le modèle de niveau local de la section [[#illustration][d'illustration]]. Les $100$ premières valeurs simulées sont écartées pour que $x_t$ soit tiré dans sa loi stationnaire. #+END_details #+NAME: ex-arima022 #+BEGIN_exercice Montrez que dans le modèle de tendance lisse, la différence seconde $\Delta^2y_t$ est un processus MA(2), dont vous calculerez les autocorrélations en fonction de \(q = \sigma_\zeta^2/\sigma_\varepsilon^2\). Comparez-les, pour $\lambda = 100$ et pour $\hat\lambda$, aux autocorrélations empiriques de la différence seconde du logarithme du PIB par tête français. Qu'en concluez-vous\nbsp{}? #+END_exercice #+ATTR_HTML: :class corrige #+BEGIN_details #+BEGIN_summary Corrigé #+END_summary Puisque $\Delta^2\mu_t = \zeta_{t-1}$, \begin{equation*} \Delta^2y_t = \zeta_{t-1} + \varepsilon_t - 2\varepsilon_{t-1} + \varepsilon_{t-2}. \end{equation*} Les autocovariances sont \(\gamma_0 = \sigma_\zeta^2 + 6\sigma_\varepsilon^2\), \(\gamma_1 = -4\sigma_\varepsilon^2\), \(\gamma_2 = \sigma_\varepsilon^2\) et $\gamma_k = 0$ pour \(k \geq 3\)\nbsp{}: $\Delta^2 y_t$ est un MA(2), et $y_t$ un ARIMA(0,2,2), d'autocorrélations \begin{equation*} \rho_1 = -\frac{4}{6 + q},\qquad \rho_2 = \frac{1}{6 + q},\qquad \rho_k = 0 \text{ pour } k \geq 3. \end{equation*} #+begin_src python :session kalman :exports code :results none print(acf(np.diff(y, 2), 4)) for l in (100, lam_hat): print(l, -4/(6 + 1/l), 1/(6 + 1/l)) #+end_src Le modèle implique $\rho_1 = -0{,}67$ et $\rho_2 = 0{,}17$ pour $\lambda = 100$, $\rho_1 = -0{,}59$ et $\rho_2 = 0{,}15$ pour $\hat\lambda$. Les autocorrélations empiriques sont $-0{,}41$, $-0{,}22$, $0{,}24$ et $0{,}01$ aux quatre premiers ordres. Le signe négatif de $\hat\rho_2$ et la valeur positive de $\hat\rho_3$, tous deux hors de la bande $\pm 1{,}96/\sqrt{197} \approx \pm 0{,}14$, sont incompatibles avec le modèle quel que soit $q$, qui impose $\rho_2 > 0$ et \(\rho_3 = 0\)\nbsp{}: le modèle de tendance lisse est mal spécifié pour cette série, ce que confirme la supériorité de la marche aléatoire avec dérive. #+END_details #+NAME: ex-h-nul #+BEGIN_exercice On considère la représentation état-mesure d'un processus AR($p$) donnée dans les exemples, avec $H = 0$, et une initialisation quelconque. Montrez que pour $t \geq p$, l'état filtré est \(a_{t|t} = (y_t, \dots, y_{t-p+1})'\) et que $P_{t|t} = 0$. Déduisez-en que, pour $t > p$, l'innovation est l'erreur de prévision \(y_t - \phi_1y_{t-1} - \dots - \phi_py_{t-p}\), de variance $\sigma^2$, et que la maximisation des termes de la log-vraisemblance correspondant aux dates $t > p$ donne l'estimateur des moindres carrés ordinaires. #+END_exercice #+ATTR_HTML: :class corrige #+BEGIN_details #+BEGIN_summary Corrigé #+END_summary À chaque date, l'observation $y_t$ est égale, sans erreur, à la première composante de l'état. La mise à jour annule donc la variance de cette composante\nbsp{}: si $F_t > 0$, le gain vaut \(K_t = P_{t|t-1}Z'/F_t\) avec \(F_t = Z P_{t|t-1} Z'\), et la première ligne de $I - K_tZ$ est nulle puisque \(ZK_t = 1\), de sorte que $P_{t|t}$ a une première ligne et une première colonne nulles. L'étape de prédiction décale l'état\nbsp{}: la composante $j+1$ de $\alpha_{t+1}$ est la composante $j$ de $\alpha_t$, connue exactement. Par récurrence, après $p$ observations, toutes les composantes de l'état sont des observations passées, connues exactement\nbsp{}: \(a_{p|p} = (y_p, \dots, y_1)'\) et $P_{p|p} = 0$. Pour $t > p$, on a alors \(a_{t|t-1} = Ta_{t-1|t-1}\), dont la première composante est \(\phi_1y_{t-1} + \dots + \phi_py_{t-p}\), et \(P_{t|t-1} = RQR'\), dont seul le premier élément, $\sigma^2$, est non nul. L'innovation est \(v_t = y_t - \phi_1y_{t-1} - \dots - \phi_py_{t-p}\), de variance $F_t = \sigma^2$, le gain est le premier vecteur de la base canonique et, à nouveau, $a_{t|t} = (y_t, \dots, y_{t-p+1})'$ et $P_{t|t} = 0$. Les termes de la log-vraisemblance pour $t > p$ sont \begin{equation*} -\frac{n-p}{2}\log 2\pi\sigma^2 - \frac{1}{2\sigma^2}\sum_{t=p+1}^n\left(y_t - \phi_1y_{t-1} - \dots - \phi_py_{t-p}\right)^2. \end{equation*} Pour tout $\sigma^2$, ils sont maximaux en $(\phi_1, \dots, \phi_p)$ lorsque la somme des carrés est minimale\nbsp{}: c'est l'estimateur des moindres carrés ordinaires de la régression de $y_t$ sur ses $p$ valeurs retardées. La vraisemblance exacte, obtenue avec l'initialisation stationnaire, ajoute les $p$ premiers termes, qui dépendent des coefficients à travers la loi stationnaire des premières observations. C'est la seule différence entre les deux estimateurs, négligeable asymptotiquement mais pas en petit échantillon (voir la note sur le [[https://stephane-adjemian.fr/posts/biais-de-l-estimateur-mco-d-un-processus-ar1/][biais de l'estimateur des moindres carrés d'un AR(1)]]). #+END_details #+NAME: ex-limites-hp #+BEGIN_exercice Déterminez les limites de la tendance de Hodrick-Prescott quand $\lambda$ tend vers zéro et vers l'infini, et interprétez la seconde dans le modèle de tendance lisse. Vérifiez numériquement sur le PIB par tête français, et expliquez pourquoi la convergence est si lente quand $\lambda$ augmente. #+END_exercice #+ATTR_HTML: :class corrige #+BEGIN_details #+BEGIN_summary Corrigé #+END_summary Quand $\lambda$ tend vers zéro, $I_n + \lambda D'D$ tend vers $I_n$ et la tendance vers la série. Quand $\lambda$ tend vers l'infini, la pénalité impose à la limite $D\mu = 0$, c'est-à-dire des différences secondes nulles\nbsp{}: la tendance est une suite affine $\mu_t = a + bt$, et minimiser $\sum(y_t - a - bt)^2$ donne la droite des moindres carrés. Dans le modèle de tendance lisse, $\lambda \to \infty$ correspond à \(\sigma_\zeta^2 \to 0\)\nbsp{}: la pente est constante et la tendance déterministe, avec un niveau et une pente initiaux diffus, dont l'estimation est celle des moindres carrés. #+begin_src python :session kalman :exports code :results none t_ = np.arange(len(y)) droite = np.polyval(np.polyfit(t_, y, 1), t_) for l in (1e2, 1e4, 1e6, 1e8, 1e10): print(l, np.max(np.abs(filtre_hp(y, l) - droite))) D = sparse.diags([1.0, -2.0, 1.0], [0, 1, 2], shape=(len(y)-2, len(y))).toarray() print(np.linalg.eigvalsh(D.T @ D)[:3]) #+end_src L'écart maximal à la droite vaut $62{,}1$ points pour $\lambda = 100$, $36{,}5$ pour $10^4$, $27{,}2$ pour $10^6$, $1{,}10$ pour $10^8$ et $0{,}012$ pour $10^{10}$. Pour le comprendre, décomposons $y$ sur une base orthonormée de vecteurs propres de $D'D$, de valeurs propres \(\nu_k\)\nbsp{}: la tendance multiplie la composante de $y$ sur le \(k\)-ème vecteur par $1/(1 + \lambda\nu_k)$. Le noyau de $D$, de dimension deux, est l'ensemble des suites affines, dont les composantes sont conservées. Les autres ne disparaissent que lorsque $\lambda\nu_k$ est grand, et la plus petite valeur propre non nulle de $D'D$, qui décroît comme $1/n^4$, ne vaut que $3{,}2\times 10^{-7}$ pour \(n = 199\)\nbsp{}: la composante correspondante, une oscillation très lente, est encore multipliée par $0{,}76$ pour $\lambda = 10^6$, et il faut $\lambda$ bien supérieur à $3\times 10^6$ pour qu'elle disparaisse. #+END_details #+NAME: ex-lisseur-regime-permanent #+BEGIN_exercice Dans le modèle de niveau local en régime permanent, montrez que le gain de lissage vaut $\bar J = -\theta$, où $\theta$ est le coefficient de la forme réduite, que le lisseur s'écrit \(a_{t|n} = (1 + \theta)\,a_{t|t} - \theta\,a_{t+1|n}\), et que la variance lissée vaut \(\bar P_{t|n} = \sigma_\varepsilon^2(1 + \theta)/(1 - \theta)\). Vérifiez ce résultat sur la série simulée de la section [[#illustration][d'illustration]]. #+END_exercice #+ATTR_HTML: :class corrige #+BEGIN_details #+BEGIN_summary Corrigé #+END_summary En régime permanent, $P_{t|t} = \sigma_\varepsilon^2\bar K$ et $P_{t+1|t} = \sigma_\varepsilon^2\bar p$, d'où, avec $T = 1$, \begin{equation*} \bar J = \frac{\bar K}{\bar p} = \frac{1}{1 + \bar p} = -\theta, \end{equation*} d'après les propriétés de la forme réduite. Comme $a_{t+1|t} = a_{t|t}$, la récurrence du lisseur s'écrit \(a_{t|n} = a_{t|t} + \bar J(a_{t+1|n} - a_{t|t}) = (1 + \theta)\,a_{t|t} - \theta\,a_{t+1|n}\)\nbsp{}: le lisseur applique à rebours à la série filtrée un lissage exponentiel de même constante $\bar K = 1 + \theta$. La variance lissée stationnaire est le point fixe de \(P = \sigma_\varepsilon^2\bar K + \theta^2(P - \sigma_\varepsilon^2\bar p)\), soit \begin{equation*} \bar P_{t|n} = \sigma_\varepsilon^2\,\frac{\bar K - \theta^2\bar p}{1 - \theta^2} = \sigma_\varepsilon^2\,\frac{(1 + \theta) + \theta(1 + \theta)}{(1 - \theta)(1 + \theta)} = \sigma_\varepsilon^2\,\frac{1 + \theta}{1 - \theta}, \end{equation*} en utilisant $\bar p = -(1 + \theta)/\theta$. Le lissage divise donc la variance filtrée $\sigma_\varepsilon^2(1 + \theta)$ par $1 - \theta$. #+begin_src python :session kalman :exports code :results none q = sigma_eta**2/sigma_eps**2 theta = (np.sqrt(q**2 + 4*q) - q - 2)/2 print(sigma_eps**2*(1 + theta)/(1 - theta), P_liss[50, 0, 0]) #+end_src Avec $q = 0{,}25$, $\theta = -0{,}610$, et la formule donne $0{,}2425$, la valeur calculée par le lisseur au milieu de l'échantillon simulé, contre $0{,}3904$ pour la variance filtrée. #+END_details