L'addition vectorielle est aussi un peu frustrante. Mettons que vous écriviez x=1:10
, i.e., implémentiez le vecteur
> x
[1] 1 2 3 4 5 6 7 8 9 10
Alors x+1
donne
> x+1
[1] 2 3 4 5 6 7 8 9 10 11
i.e., ajoute 1 à tous les éléments du vecteur
Attention en particulier lorsque l'on cherche à accéder à un ensemble d'indices dans une liste, un vecteur ou une matrice
end
pour accéder au dernier élément d'une matrice/liste/vecteur..length
(listes ou vecteurs), nchar
(chaînes de caractères), dim
(matrices.. attention, renvoie 2 valeurs), nrow
et ncol
(matrices)tidyverse
(ensemble de librairies facilitant la manipulation des données - data wrangling)> A = data.frame(colonne_1 = runif(10),
colonne_2 = c(rep("rouge", 5),
rep("vert", 5)))
> A
colonne_1 colonne_2
1 0.91636576 rouge
2 0.61324886 rouge
3 0.07157395 rouge
4 0.47366452 rouge
5 0.32406160 rouge
6 0.59960934 vert
7 0.12232243 vert
8 0.60096836 vert
9 0.74122462 vert
10 0.11164494 vert
> summary(A)
colonne_1 colonne_2
Min. :0.07157 Length:10
1st Qu.:0.17276 Class :character
Median :0.53664 Mode :character
Mean :0.45747
3rd Qu.:0.61018
Max. :0.91637
Une capacité très attrayante de R : il est possible de nommer les entrées dans toute liste (on a déjà vu ça), mais aussi tout vecteur, toute matrice ou data frame
r$> v = c(alpha = 2, beta = 3, gamma = 4, delta = 5)
r$> v
alpha beta gamma delta
2 3 4 5
est un vecteur, et v["beta"]
renvoie 3..
r$> v = c(1,2,3)
r$> names(v) = c("alpha", "beta", "gamme")
r$> v
alpha beta gamme
1 2 3
Ou encore, pour une matrice
r$> A = matrix(c(1,2,3,4), nrow = 2, byrow = TRUE)
r$> rownames(A) = c("alpha","beta")
r$> colnames(A) = c("chose","truc")
r$> A
chose truc
alpha 1 2
beta 3 4
r$> A[1,2]
[1] 2
r$> A["alpha","truc"]
[1] 2
if (condition est vraie) {
liste de choses à faire
}
Même si liste de choses à faire
est une seule chose, il vaut mieux utiliser des accolades { }
if (condition est vraie) {
liste de choses à faire
} else if (une autre condition est vraie) {
...
} else {
...
}
for
s'applique à des listes ou des vecteurs
for (i in 1:10) {
quelque chose utilisant l'entier i
}
for (j in c(1,3,4)) {
quelque chose utilisant l'entier j
}
for (n in c("truc", "muche", "chose")) {
quelque chose utilisant la chaîne n
}
for (m in list("truc", "muche", "chose", 1, 2)) {
quelque chose utilisant la chaîne n ou l'entier n, selon les cas
}
Fonction très utile (et autres fonctions dans la même veine, sapply
, vapply
, mapply
)
Applique une fonction à chaque élément d'une liste,d'un vecteur ou d'une matrice
Il existe des versions parallèles (p. ex., parLapply
) que nous verrons plus tard
l = list()
for (i in 1:10) {
l[[i]] = runif(i)
}
lapply(X = l, FUN = mean)
ou, pour renvoyer un vecteur
unlist(lapply(X = l, FUN = mean))
ou
sapply(X = l, FUN = mean)
On peut choisir des éléments non évidents dans une liste
l = list()
for (i in 1:10) {
l[[i]] = list()
l[[i]]$a = runif(i)
l[[i]]$b = runif(2*i)
}
sapply(X = l, FUN = function(x) length(x$b))
donne
[1] 2 4 6 8 10 12 14 16 18 20
Il suffit de se souvenir que l'argument de la fonction est un élément de la liste (l[[1]]
, l[[2]]
, etc., ici)
# Supposon qu'on veuille faire varier 3 paramètres
variations = list(
p1 = seq(1, 10, length.out = 10),
p2 = seq(0, 1, length.out = 10),
p3 = seq(-1, 1, length.out = 10)
)
# Créons la liste
tmp = expand.grid(variations)
PARAMS = list()
for (i in 1:dim(tmp)[1]) {
PARAMS[[i]] = list()
for (k in 1:length(variations)) {
PARAMS[[i]][[names(variations)[k]]] = tmp[i, k]
}
}
Il reste une boucle, mais une fois la liste constituée, on peut la découper pour la distribuer entre machines, ou l'utiliser avec parLapply
deSolve
:The functions provide an interface to the FORTRAN functions 'lsoda', 'lsodar', 'lsode', 'lsodes' of the 'ODEPACK' collection, to the FORTRAN functions 'dvode', 'zvode' and 'daspk' and a C-implementation of solvers of the 'Runge-Kutta' family with fixed or variable time steps
Donc vous bénéficiez d'années d'experience: ODEPACK est une librairie de solveurs numériques écrits à l'origine en Fortran (77!) développés au Lawrence Livermore National Laboratory (LLNL) à partir des années 70
Voir l'aide du package pour des détails
Comme avec la majorité des algorithmes, il faut écrire une fonction qui renvoie la valeur des dérivées (droite du signes égal) du système (le champ de vecteurs) en un point donné de l'espace (et potentiellement du temps), puis appeler cette fonction depuis le solveur
library(deSolve)
rhs_logistic <- function(t, x, p) {
dN <- p$r * x[1] *(1-x[1]/p$K)
return(list(dN))
}
params = list(r = 0.1, K = 100)
IC = 50
times = seq(0, 100, 1)
sol <- ode(IC, times, rhs_logistic, params)
with(as.list(x), {
On peut aussi faire la chose suivante: en utilisant with(as.list(x, {
, on peut accéder au contenu de x
directement, s'il est nommé
rhs_logistic <- function(t, x, p) {
with(as.list(x), {
dN <- p$r * N *(1-N/p$K)
return(list(dN))
})
}
params = list(r = 0.1, K = 100)
IC = c(N = 50)
times = seq(0, 100, 1)
sol <- ode(IC, times, rhs_logistic, params)
Il est donc important de nommer le contenu de la condition initiale: avant, on avait fait simplement IC = 50
, ici on doit faire IC = c(N = 50)
On peut aussi ajouter p
aux arguments de as.list
pour utiliser le contenu de p
sans avoir besoin de préfixer par p$
library(deSolve)
rhs_logistic <- function(t, x, p) {
with(as.list(c(x, p)), {
dN <- r * N *(1-N/K)
return(list(dN))
})
}
params = list(r = 0.1, K = 100)
IC = c(N = 50)
times = seq(0, 100, 1)
sol <- ode(IC, times, rhs_logistic, params)
Attention de ne pas avoir une variable et un paramètre avec le même nom..
lsoda
lsoda
change automatiquement entre méthodes stiff et nonstiff
Vous pouvez aussi spécifier d'autres méthodes: "lsode", "lsodes", "lsodar", "vode", "daspk", "euler", "rk4", "ode23", "ode45", "radau", "bdf", "bdf_d", "adams", "impAdams" ou "impAdams_d" ,"iteration" (ce dernier pour les systèmes en temps discret)
ode(y, times, func, parms, method = "ode45")