Le CRAN propose une Task View sur les équations différentielles.
Une équation différentielle est une équation entre une ou plusieurs fonctions inconnues et leurs dérivées. Elle décrit comment une fonction varie par rapport à une ou plusieurs variables (souvent le temps et/ou l’espace) et par rapport à ses dérivées.
Il y a différentes facon de classifier les équations différentielles :
les équations peuvent être stochastique (la quantité inconnue est aléatoire) ou déterministe (la quantité inconnue est déterministe).
les équations peuvent porter sur des fonctions à une seule variable (équation différentielle ordinaire) ou à plusieurs variables (équation aux dérivées partielles).
les équations peuvent inclure des fonctions dont la dérivée à un certain pas de temps dépend de la dérivée à un pas de temps précédent (équation différentielle à retard ou differential equations delay). Elles peuvent aussi inclure des relations algébriques entre les variables (équation différentielle algébrique).
Il existe plusieurs packages R permettant de résoudre ces équations et d’ajuster ces modèles à de la donnée. Ici, seuls les package deSolve et diffeqr sont utilisés pour résoudre des ED.
Le package deSolve
permet de résoudre numériquement des équations simples.
install.packages("deSolve")
library(tidyverse)
library(GGally)
library(deSolve)
library(fda)
theme_set(theme_bw())
On cherche à résoudre \(y' = ay\) avec condition initiale \(y(0) = y_0\). On commence par coder l’équation différentielle: - t
représente le temps courant - Y
représente l’état courant du système - parameters
stocke les paramètres du modèle (ici \(a\))
function(t, Y, parameters) {
model <-with(as.list(parameters), {
-a * Y
dy =list(dy)
}) }
On renseigne ensuite la jacobienne \(\frac{\partial y'}{\partial y}\)
function(t, Y, parameters) {
jac <-with(as.list(parameters), {
1, 1] <- a
PD[return(PD)
}) }
On peut ensuite résoudre l’EDO pour \(a = 1\) et \(y_0 = 1\) sur l’intervalle \([0, 1]\) des pas de temps de longeur \(0.01\) comme suit:
c(a = 1)
params <- c(1)
y0 <- seq(0, 1, by = 0.01)
times <- matrix(0, nrow = 1, ncol = 1)
PD <- ode(y0, times, model, parms = params, jacfun = jac) out_atome <-
Le résultat est une matrice: - une colonne pour le temps (reprend les valeurs de times
) - une colonne par dimension dans le système d’équations différentielles
On peut vérifier que la solution numérique (en bleu) est confondue avec la solution analytique (en rouge).
plot_data <- data.frame(out_atome) %>%
rename(numeric = X1) %>%
mutate(analytic = exp(-time)) %>%
pivot_longer(cols = -time,
names_to = "type",
values_to = "y")
ggplot(plot_data, aes(x = time, y = y, color = type)) +
geom_line() +
ylim(0, 1) +
theme(legend.position = c(0.95, 0.95),
legend.justification = c(1, 1),
legend.background = element_rect(fill = NA))
ode
utilise la méthode de Runge-Kutta pour calculer \(y(t)\) et renvoie uniquement les valeurs \(y(0), y(0.01), \dots, y(1)\) mais fait néanmoins appel à des points intérmédiaires lors du calcul. On peut s’en convaincre en comparant les valeurs finales (\(y(1)\)) obtenues avec times = seq(0, 1, by = 0.01)
et times = seq(0, 1, by = 1)
.
On peut diagnostiquer la réussite de l’intégration numérique via la commande diagnostics
diagnostics(out_atome)
##
## --------------------
## lsoda return code
## --------------------
##
## return code (idid) = 2
## Integration was successful.
##
## --------------------
## INTEGER values
## --------------------
##
## 1 The return code : 2
## 2 The number of steps taken for the problem so far: 102
## 3 The number of function evaluations for the problem so far: 133
## 5 The method order last used (successfully): 6
## 6 The order of the method to be attempted on the next step: 6
## 7 If return flag =-4,-5: the largest component in error vector 0
## 8 The length of the real work array actually required: 36
## 9 The length of the integer work array actually required: 21
## 14 The number of Jacobian evaluations and LU decompositions so far: 0
## 15 The method indicator for the last succesful step,
## 1=adams (nonstiff), 2= bdf (stiff): 1
## 16 The current method indicator to be attempted on the next step,
## 1=adams (nonstiff), 2= bdf (stiff): 1
##
## --------------------
## RSTATE values
## --------------------
##
## 1 The step size in t last used (successfully): 0.01
## 2 The step size to be attempted on the next step: 0.01
## 3 The current value of the independent variable which the solver has reached: 1.00002
## 4 Tolerance scale factor > 1.0 computed when requesting too much accuracy: 0
## 5 The value of t at the time of the last method switch, if any: 0
##
Source https://kinglab.eeb.lsa.umich.edu/480/nls/de.html Nous considérons le modèle différentiel classique en épidémiologie.
# Define differential System
function (t, state, parameters) {
closed.sir.model <-## first extract the state variables
state[1]
S <- state[2]
I <- state[3]
R <-## now extract the parameters
parameters[1]
beta <- parameters[2]
gamma <- S + I + R
N <-## now code the model equations
-beta * S * I/N
dSdt <- beta * S * I/N - gamma * I
dIdt <- gamma * I
dRdt <-## combine results into a single vector
c(dSdt,dIdt,dRdt)
dxdt <-## return result as a list!
list(dxdt)
}
Define parameters and times of evaluation
c(beta = 400,gamma = 365/13)
parms <-# times stamps
seq(from = 0,to = 60/365,by = 1/365/4)
times <-# initial conditions
c(S = 999,I = 1,R = 0) xstart <-
Solving with ODE
out.SIR <- ode(func = closed.sir.model,
y = xstart,
times = times,
parms = parms,
method = 'lsodar') %>%
as.data.frame()
And plot
%>%
out.SIR gather(variable,value,-time) %>%
ggplot(aes(x = time,y = value,color = variable)) +
geom_line(size = 2) +
labs(x = 'time (yr)',y = 'number of individuals')
Il s’agit d’une modélisation idéalisée de l’atmosphère. X, Y et Z représentent respectivement les variations verticale et horizontale de la température et le flux de convection.
\[ \left\{ \begin{align} X' &= aX + YZ \\ Y' &= b(Y-Z) \\ Z' &= -XY + cY -Z \\ \end{align} \right. \]
seq(0, 100, by = 0.01)
times <-
-8/3
a <- -10
b <- 28
c <-
function(t, y, parms) {
lorenz <-with(as.list(y), {
a * X + Y * Z
dX <- b * (Y - Z)
dY <- -X * Y + c * Y - Z
dZ <-list(c(dX, dY, dZ))
})
}
ode(y = c(X = 1, Y = 1, Z = 1), times = times, func = lorenz, parms = NULL)
out_lorenz <-
df_lorenz <- out_lorenz %>%
as_tibble() %>%
mutate_all(as.numeric)
df_lorenz
## # A tibble: 10,001 x 4
## time X Y Z
## <dbl> <dbl> <dbl> <dbl>
## 1 0 1 1 1
## 2 0.01 0.985 1.01 1.26
## 3 0.02 0.973 1.05 1.52
## 4 0.03 0.965 1.11 1.80
## 5 0.04 0.962 1.19 2.09
## 6 0.05 0.964 1.29 2.40
## 7 0.06 0.973 1.41 2.74
## 8 0.07 0.990 1.55 3.11
## 9 0.08 1.02 1.72 3.52
## 10 0.09 1.06 1.91 3.97
## # … with 9,991 more rows
ggpairs(df_lorenz,
lower = list(continuous = wrap("points", size = 0.1)))
\[ \begin{align} A+B \xrightarrow{k_A} 2A \\ B+C \xrightarrow{k_B} 2B \\ C+A \xrightarrow{k_C} 2C \\ \end{align} \]
\[ \left\{ \begin{align} \partial_t n_A = n_A (k_A n_B - k_C n_C) \\ \partial_t n_B = n_B (k_B n_C - k_A n_A) \\ \partial_t n_C = n_C (k_C n_A - k_B n_B) \\ \end{align} \right. \]
seq(0, 30, by = 0.01)
times <-
1
k_A <- 1
k_B <- 2
k_C <-
function(t, y, params) {
bz <-with(as.list(y), {
A * (k_A * B - k_C * C)
dA <- B * (k_B * C - k_A * A)
dB <- C * (k_C * A - k_B * B)
dC <-list(c(dA, dB, dC))
})
}
ode(y = c(A = 0.6, B = 0.6, C = 0.3), times = times, func = bz, parms = NULL)
out_bz <-
%>%
out_bz as_tibble() %>%
mutate_all(as.numeric) %>%
pivot_longer(-time, names_to = "variable", values_to = "value") %>%
ggplot() +
aes(x = time, y = value, color = variable) +
geom_line()
La résolution d’EDP est plus complexe et consiste à transformer les EDPs en EDOs en utilisant la méthode des différences finies.
On illustre la démarche sur un modèle de diffusion de pestes (des aphides) sur une rangée de plantes positionnées entre \(x = 0\) et \(x = 60\).
\[ \frac{\partial N}{\partial t} = - \frac{\partial F}{\partial x} + g \times N \]
où le flux diffusif est donné par \(F = -D \frac{\partial N}{\partial x}\) et les contraintes stipulent que la densité d’aphides tombe à \(0\) aux deux bouts de la rangée de plantes: \(\forall t \geq 0, N(x=0, t) = N(x=60, t) = 0\).
Au temps initial, les aphides ne sont présentes qu’au milieu de la rangée de plantes: \[ N(x, t = 0) = \begin{cases} 1 & \text{if} \quad x = 30 \\ 0 & \text{else} \end{cases} \]
La méthodes des différences finies consiste à diviser le domaine en boîtes et à discrétiser l’équation comme suit \[ \frac{dN_i}{dt} = - \frac{F_{i, i+1} - F_{i-1, i}}{\Delta x_i} + g\times N_i \] où \(N_i\) représente la densité d’aphide au milieu de la boîte tandis que les flux sont définies aux interfaces entre boîtes: \[ F_{i-1, i} = -D_{i, i-1} \times \frac{N_i - N_{i-1}}{\Delta x_{i-1, i}} \] pour se ramener à un système d’EDOs.
On commence par définir les équations du modèle
function(t, APHIDS, parameters) {
Aphid <-with(as.list(parameters), {
## taille des boîtes
c(0.5, rep(1, numboxes - 1), 0.5)
deltax <-## valeurs du flux aux interfaces
-D * diff(c(0, APHIDS, 0)) / deltax
Flux <-## valeurs des dérivées
-diff(Flux) / delx + APHIDS * r
dAPHIDS <-# the return value
list(dAPHIDS)
}) }
puis les paramètres du modèle et de la grille de discretisation:
list(
params <- 0.3, # m2/day diffusion rate
D <- 0.01, # /day net growth rate
r <- 1, # m thickness of boxes
delx <- 60,
numboxes <-# distance of boxes on plant, m, 1 m intervals
seq(from = 0.5, by = delx, length.out = numboxes)
Distance <- )
et enfin les conditions intiales
# Initial conditions: # ind/m2
rep(0, times = numboxes)
APHIDS <-30:31] <- 1
APHIDS[# initialise state variables
c(APHIDS = APHIDS) state <-
on peut alors laisser la densité évoluer sur 200 jours avec un rendu par jour:
ode.1D(state, times = 0:200, Aphid, parms = params,
out_aphide <-nspec = 1, names = "Aphid")
Le résultat est comme auparavant une matrice avec la première colonne pour le temps et une colonne par EDO dans la discrétisation.
On peut utiliser ce résultat pour voir la diffusion des aphides dans les plantes au cours du temps:
%>%
out_aphide data.frame %>%
pivot_longer(cols = -time,
names_to = "location",
names_pattern = "APHIDS(.*)",
values_to = "density") %>%
mutate(location = as.integer(location)) %>%
ggplot(aes(x = time, y = location, fill = density)) +
geom_tile() +
scale_fill_viridis_c()
Cet exemple est tiré du document : https://cran.r-project.org/web/packages/deSolve/vignettes/deSolve.pdf .
Le modèle logistique est un modèle de dynamique de population simple dans lequel une population donnée évolue jusqu’à atteindre un plateau (la capacité biotique du milieu noté M). La dynamique de la population peut être représentée par l’ED suivante : \(x'(t)=r.x(t).[\frac{1-x(t)}{M}]\). Le terme densité-dépendant \(\frac{1-x(t)}{M}\) peut avoir un effet sur la population avec un temps de retard. L’ED peut alors être réécrite : \(x'(t)=r.x(t).[\frac{1-x(t - \tau)}{M}]\). Sous cette forme l’ED est une équation différentielle à retard (EDR).
Dans le cas d’une population de lemming, le lag est fixé à 9 mois (0.74 année), soit le temps de croissance d’un lemming jusqu’au stade adulte. Le paramètre r est fixé sur la base de données expérimentales et la capacité biotique du milieu (M) est fixée arbitrairement à 19.
Les lignes de codes qui suivent permettent de simuler et de visualiser l’évolution d’une population de lemming (\(1^{ère}\) figure). La deuxième figure représente l’évolution de \(x(t)\) en fonction de \(x(t-\tau)\).
# DDE function
function(t, y, parms) {
derivs <-if (t < 0) {
19
lag <-else {
} lagvalue(t - 0.74)
lag <-
} r * y * (1 - lag / m)
dy <-list(dy, dy = dy)
}
# parameters
3.5; m <- 19
r <-
# initial values and times
c(y = 19.001)
yinit <- seq(-0.74, 40, by = 0.01)
times <-
dede(y = yinit, times = times, func = derivs,
yout <-parms = NULL, atol = 1e-10)
df_out <- yout %>%
as_tibble() %>%
mutate_all(as.numeric) %>%
mutate(yend = lead(y), dy.yend = lead(dy.y))
ggplot(df_out) +
aes(x = time, y = y) +
geom_line()
ggplot(df_out) +
aes(x = y, y = dy.y, xend = yend, yend = dy.yend) +
geom_segment() +
labs(x = "y", y = "y'")
## Warning: Removed 1 rows containing missing values (geom_segment).
Il s’agit d’une interface R pour utiliser le package Julia DifferentialEquations.jl. Le package est disponible sur le CRAN et sur GitHub.
Pour l’utiliser il faut installer Julia, en le téléchargeant ici et le package DifferentialEquations.jl. Attention le package R JuliaCall qui permet d’appeler des fonctions julia depuis R ne fonctionne pas avec la version 4.0 de R au moment du test donc utilisez la version 3.6.
Je conseille de tester le package Julia dans un premier temps. L’instruction qui suit permet d’exécuter du code julia dans un fichier Rmarkdown:
JuliaCall::julia_markdown_setup() julia <-
## Julia version 1.5.1 at location /usr/local/julia1.5.1/bin will be used.
## Loading setup script for JuliaCall...
## Finish loading setup script for JuliaCall.
using Pkg
"Plots", "DifferentialEquations"]) Pkg.add([
using DifferentialEquations, Plots
function lorenz(du,u,p,t)
1] = p[1]*(u[2]-u[1])
du[2] = u[1]*(p[2]-u[3]) - u[2]
du[3] = u[1]*u[2] - p[3]*u[3]
du[end
## lorenz (generic function with 1 method)
= [1.0;0.0;0.0] u0
## 3-element Array{Float64,1}:
## 1.0
## 0.0
## 0.0
= (0.0,100.0) tspan
## (0.0, 100.0)
= [10.0,28.0,8/3] p
## 3-element Array{Float64,1}:
## 10.0
## 28.0
## 2.6666666666666665
= ODEProblem(lorenz,u0,tspan,p) prob
## [36mODEProblem[0m with uType [36mArray{Float64,1}[0m and tType [36mFloat64[0m. In-place: [36mtrue[0m
## timespan: (0.0, 100.0)
## u0: [1.0, 0.0, 0.0]
= solve(prob, saveat=0.01) sol
## retcode: Success
## Interpolation: 1st order linear
## t: 10001-element Array{Float64,1}:
## 0.0
## 0.01
## 0.02
## 0.03
## 0.04
## 0.05
## 0.06
## 0.07
## 0.08
## 0.09
## ⋮
## 99.92
## 99.93
## 99.94
## 99.95
## 99.96
## 99.97
## 99.98
## 99.99
## 100.0
## u: 10001-element Array{Array{Float64,1},1}:
## [1.0, 0.0, 0.0]
## [0.9179244486277306, 0.2663399883958265, 0.0012638961610231109]
## [0.8679193806275423, 0.5117405221648474, 0.0046554489845949155]
## [0.8453600810424241, 0.7446542578856288, 0.009835866378798786]
## [0.8468056451056966, 0.9723322686162557, 0.01673452988174231]
## [0.8697858478642188, 1.2011328308675078, 0.025486243607962873]
## [0.9126414552178186, 1.4367663939448458, 0.03640115766854124]
## [0.9743847413621038, 1.6845201726702408, 0.0499584260358821]
## [1.0546231178470253, 1.9494049510715725, 0.0668156858164365]
## [1.1534564425013134, 2.236343236012357, 0.08784004081242848]
## ⋮
## [6.308988418917138, 10.034508455329648, 16.666741893400562]
## [6.694294477197805, 10.6616223774606, 16.89262743745928]
## [7.103490720791537, 11.307921316239156, 17.19617808515391]
## [7.535723915953175, 11.967755076126197, 17.584159255358543]
## [7.989771855958641, 12.634312203856176, 18.06363047390422]
## [8.463949520591994, 13.298647824439136, 18.64123724761683]
## [8.955627647759492, 13.948244596296133, 19.322132634934754]
## [9.461062547781847, 14.56883567414296, 20.110058358591274]
## [9.97537965430362, 15.143884806010783, 21.00643286956427]
,vars=(1,2,3)) plot(sol
Le package diffeqr permet d’utiliser le package julia depuis R:
diffeqr::diffeq_setup() de <-
Définition de la fonction dérivée:
function(u,p,t) {
f <- p[1]*(u[2]-u[1])
du1 = u[1]*(p[2]-u[3]) - u[2]
du2 = u[1]*u[2] - p[3]*u[3]
du3 =return(c(du1,du2,du3))
}
Les paramètres sont contenus dans un vecteur p
.
c(1.0,0.0,0.0)
u0 <- c(0.0,100.0)
tspan <- c(10.0,28.0,8/3)
p <- de$ODEProblem(f, u0, tspan, p)
prob <- de$solve(prob, saveat=0.01) sol <-
Les méthodes numériques pour la résolution sont très nombreuses. Voir la page ODE solvers.
La solution sol$u
est une liste de vecteurs, et sol$u[i]
est le vecteur u[i] au temps sol$t[i]
. On peut le transformer en matrice R avec sapply
:
sapply(sol$u,identity) mat <-
Chaque ligne est une série temporelle, on peut transformer la solution en data.frame
as.data.frame(t(mat))
udf <-matplot(sol$t,udf,"l",col=1:3)
::plot_ly(udf, x = ~V1, y = ~V2, z = ~V3, type = 'scatter3d', mode = 'lines') plotly
## Warning: `arrange_()` is deprecated as of dplyr 0.7.0.
## Please use `arrange()` instead.
## See vignette('programming') for more help
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
diffeqr
propose une fonction qui permet de compiler cette fonction. La fonction R sera traduite en Julia et compilée dans le langage LLVM qui est un dialecte du langage C. Ce langage et sa compilation sont le “moteur” de Julia qui lui permet d’avoir des performances comparables aux langages compilés comme le C++ ou le Fortran. diffeqr::jitoptimize_ode(de,prob)
prob2 <- de$solve(prob2, de$Tsit5() ) sol <-
On fixe ici la méthode de résolution avec Tsit5 (Tsitouras 5/4 Runge-Kutta).
Pour améliorer un peu plus les performances, on peut utiliser la version Julia de la fonction dérivée. Transformons toutes les variables R en variables Julia:
JuliaCall::julia_eval("
julf <-function julf(du,u,p,t)
du[1] = 10.0*(u[2]-u[1])
du[2] = u[1]*(28.0-u[3]) - u[2]
du[3] = u[1]*u[2] - (8/3)*u[3]
end")
::julia_assign("u0", u0)
JuliaCall::julia_assign("p", p)
JuliaCall::julia_assign("tspan", tspan)
JuliaCall JuliaCall::julia_eval("ODEProblem(julf, u0, tspan, p)")
prob3 <- de$solve(prob3,de$Tsit5()) sol <-
system.time({ for (i in 1:100){ de$solve(prob, de$Tsit5()) }})
## user system elapsed
## 9.110 0.256 9.367
system.time({ for (i in 1:100){ de$solve(prob2, de$Tsit5()) }})
## user system elapsed
## 0.167 0.040 0.208
system.time({ for (i in 1:100){ de$solve(prob3, de$Tsit5()) }})
## user system elapsed
## 0.258 0.080 0.338
Les performances de diffeqr
seront plus intéressantes dans le cas des EDS. En effet, pour résoudre numériquement ce type d’équation, nous avons besoin de calculer la solution d’une EDO plusieurs milliers de fois. Le gain qui peut paraître minime pour une EDO devient mille fois plus intéressant pour une EDS.
On utilise deux fonctions f
et g
, où du = f(u,t)dt + g(u,t)dW_t
function(u,p,t) {
f <- p[1]*(u[2]-u[1])
du1 = u[1]*(p[2]-u[3]) - u[2]
du2 = u[1]*u[2] - p[3]*u[3]
du3 =return(c(du1,du2,du3))
} function(u,p,t) {
g <-return(c(0.3*u[1],0.3*u[2],0.3*u[3]))
} c(1.0,0.0,0.0)
u0 <- c(0.0,1.0)
tspan <- c(10.0,28.0,8/3)
p <-
c(0.0,100.0)
tspan <- de$SDEProblem(f,g,u0,tspan,p)
prob <- diffeqr::jitoptimize_sde(de,prob)
fastprob <- de$solve(fastprob,saveat=0.005)
sol <- as.data.frame(t(sapply(sol$u,identity)))
udf <-::plot_ly(udf, x = ~V1, y = ~V2, z = ~V3, type = 'scatter3d', mode = 'lines') plotly
desolve
library(deSolve)
function(t, state, parameters) {
Lorenz <-with(as.list(c(state, parameters)), {
a * X + Y * Z
dX <- b * (Y - Z)
dY <- -X * Y + c * Y - Z
dZ <-list(c(dX, dY, dZ))
})
}
c(a = -8/3, b = -10, c = 28)
parameters <- c(X = 1, Y = 1, Z = 1)
state <- seq(0, 100, by = 0.01)
times <- ode(y = state, times = times, func = Lorenz, parms = parameters)
out <-
function (i){
lorenz_solve <- c(X = runif(1), Y = runif(1), Z = runif(1))
state <- c(a = -8/3 * runif(1), b = -10 * runif(1), c = 28 * runif(1))
parameters <- ode(y = state, times = times, func = Lorenz, parms = parameters)
out <- }
system.time({ lapply(1:1000,lorenz_solve) })
## user system elapsed
## 210.109 0.245 210.388
function (prob,i,rep){
prob_func <-$remake(prob,u0=runif(3)*u0,p=runif(3)*p)
de
} de$EnsembleProblem(fastprob, prob_func = prob_func, safetycopy=FALSE) ensembleprob =
system.time({ de$solve(ensembleprob,de$Tsit5(),de$EnsembleSerial(),trajectories=1000,saveat=0.01) })
## user system elapsed
## 88.042 2.684 90.733
Le package diffeqr
fonctionne également sur GPU, vous pouvez voir un exemple dans ce billet de blog.
On chercher mainenant à estimer les paramètres structurels d’un système diférentiel à partir d’observations bruitées. On l’applique sur le SIR.
20
sigma <- out.SIR
noisy <-$S <- pmax(out.SIR$S + rnorm(length(out.SIR$time),0,sigma),0)
noisy$I <- pmax(out.SIR$I + rnorm(length(out.SIR$time),0,sigma),0)
noisy$R <- pmax(out.SIR$R + rnorm(length(out.SIR$time),0,sigma),0)
noisy
%>%
noisy gather(variable,value,-time) %>%
ggplot(aes(x = time,y = value,color = variable)) +
geom_point(size = 2) +
theme_classic() +
labs(x = 'time (yr)',y = 'number of individuals')
noisy[,2:4] observ <-
Utiliser une méthode des moindres carrés habituelles est rendue compliquée par le fait que la fonction de régression \(f\) est solution d’une quat diff donc n’a pas de solution explicite. De plus, chaque évaluation de la fonction (par un schéma numérique) est couteux d’un point de vue computationnel.
Une autre approche est d’exprimer \(f\) dans une base (spline par exemple), cette fonction devra d’une part s’ajuster aux donnnées et d’autre part être solution du système (qui est introduit comme une pénalité). Cette méthode qui date de 2007, est implémentée dans le package pcode
La méthode est décrite dans la vignette du pacakge.
On définit dabord une base de décomposition pour les fonctions (package fda)
#" basis list
seq(0,max(times),length.out=21)
knots <-#order of basis functions
4
norder <-#number of basis funtions
length(knots) + norder - 2
nbasis <-#creating Bspline basis
create.bspline.basis(c(0,max(times)),nbasis,norder,breaks = knots)
basis_dim1 <- list(basis_dim1,basis_dim1,basis_dim1) basis =
Puis on optimise:
pcode(data = observ, time = times, ode.model = closed.sir.model,
pcode.result <-par.initial = c(100,1), par.names = c('beta','gamma'),state.names = c('S','I','R'),
basis.list = basis, lambda = 1e2)
sessionInfo()
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-conda_cos6-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.5 LTS
##
## Matrix products: default
## BLAS/LAPACK: /usr/share/miniconda/envs/finistR2020/lib/libopenblasp-r0.3.10.so
##
## locale:
## [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=C.UTF-8 LC_COLLATE=C.UTF-8
## [5] LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
## [7] LC_PAPER=C.UTF-8 LC_NAME=C.UTF-8
## [9] LC_ADDRESS=C.UTF-8 LC_TELEPHONE=C.UTF-8
## [11] LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] fda_5.1.5.1 Matrix_1.2-18 deSolve_1.28
## [4] GGally_2.0.0 ggdist_2.2.0 distributional_0.2.0
## [7] DT_0.15 forcats_0.5.0 stringr_1.4.0
## [10] dplyr_1.0.2 purrr_0.3.4 readr_1.3.1
## [13] tidyr_1.1.2 tibble_3.0.3 ggplot2_3.3.2
## [16] tidyverse_1.3.0
##
## loaded via a namespace (and not attached):
## [1] httr_1.4.2 jsonlite_1.7.1 viridisLite_0.3.0
## [4] splines_3.6.3 modelr_0.1.8 assertthat_0.2.1
## [7] highr_0.8 blob_1.2.1 cellranger_1.1.0
## [10] yaml_2.2.1 pillar_1.4.6 backports_1.1.9
## [13] lattice_0.20-41 glue_1.4.2 readODS_1.7.0
## [16] digest_0.6.25 RColorBrewer_1.1-2 rvest_0.3.6
## [19] colorspace_1.4-1 htmltools_0.5.0.9000 plyr_1.8.6
## [22] JuliaCall_0.17.1.9000 pkgconfig_2.0.3 broom_0.7.0
## [25] haven_2.3.1 scales_1.1.1 jpeg_0.1-8.1
## [28] generics_0.0.2 farver_2.0.3 ellipsis_0.3.1
## [31] withr_2.2.0 lazyeval_0.2.2 cli_2.0.2
## [34] magrittr_1.5 crayon_1.3.4 readxl_1.3.1
## [37] diffeqr_1.0.0 evaluate_0.14 fs_1.5.0
## [40] fansi_0.4.1 xml2_1.3.2 data.table_1.12.8
## [43] tools_3.6.3 hms_0.5.3 lifecycle_0.2.0
## [46] plotly_4.9.2.1 munsell_0.5.0 reprex_0.3.0
## [49] compiler_3.6.3 rlang_0.4.7 grid_3.6.3
## [52] rstudioapi_0.11 htmlwidgets_1.5.1 crosstalk_1.1.0.1
## [55] labeling_0.3 rmarkdown_2.3 gtable_0.3.0
## [58] codetools_0.2-16 DBI_1.1.0 reshape_0.8.8
## [61] R6_2.4.1 lubridate_1.7.9 knitr_1.29
## [64] utf8_1.1.4 stringi_1.4.6 Rcpp_1.0.5
## [67] png_0.1-7 vctrs_0.3.4 dbplyr_1.4.4
## [70] tidyselect_1.1.0 xfun_0.16