L’objectif de ce chapitre est de définir ses propres fonctions. La première étape est d’introduire les structures de contrôle, c’est à dire les boucle for et des instructions if.

Structure de contrôle

Exécution conditionnelle

if(condition) {branche.vraie} else{branche.faux}. Si la condition est vérifié on éxécute le code dans la branche.vraie, sinon on éxécute le code dans la branche.fausse.

# Réalisation d'une variable aléatoire de loi binomiale
bin_number = rbinom(1, size = 10, prob = 0.4)
bin_number
## [1] 7
# L'opérateur %% est l'opérateur modulo !
if(bin_number %% 2 == 0){
  print("le nombre est pair")
}else{
  print("le nombre est impair")
}
## [1] "le nombre est impair"

Boucle

R n’est pas un langage optimisé pour l’usage des boucles for, elles sont à proscrire autant que possible.

for(variables in suite){expr}. Les éléments dans suite ne sont pas nécessairement des nombres.

# Impression des 10 premiers entier 
for(k in 1:10){
  print(k)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
# Impression des entier par pas de 3
for(k in seq(1, 10, 3)){
  print(k)
}
## [1] 1
## [1] 4
## [1] 7
## [1] 10

Lorsque le nombre d’itération n’est pas connu à l’avance, l’instruction while est utilisée.

while(condition){expr}. Tant que la condition est vérifié, on exécute les instructions.

x <- 1
while(x < 30){
  print(x)
  x <- exp(x)
}
## [1] 1
## [1] 2.718282
## [1] 15.15426
x
## [1] 3814279

Une autre façon de définir une boucle est l’instruction repeat qui va de paire avec l’instruction break.

repeat{expr; if(condition) break}

x <- 1
repeat{
  print(x)
  x <- exp(x)
  if(x > 40) break
}
## [1] 1
## [1] 2.718282
## [1] 15.15426
x
## [1] 3814279

Il est possible d’inclure des éxécutions conditionelles dans une boucle. Par exemple, si nous souhaitons (pour d’obscures raisons) créer un vecteur contenant des entiers de \(1\) à \(100\) sans les multiples de \(10\) et afficher les multiples de \(10\) alors

# Initialisation du vecteur souhaité
vec = vector()
j = 0
for(k in 1:100){
  if(k %% 10 == 0){
    print(k)
  }else{
    j <- j+1
    vec[j] <- k
  }
}
## [1] 10
## [1] 20
## [1] 30
## [1] 40
## [1] 50
## [1] 60
## [1] 70
## [1] 80
## [1] 90
## [1] 100
vec
##  [1]  1  2  3  4  5  6  7  8  9 11 12 13 14 15 16 17 18 19 21 22 23 24 25 26 27
## [26] 28 29 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 47 48 49 51 52 53 54 55
## [51] 56 57 58 59 61 62 63 64 65 66 67 68 69 71 72 73 74 75 76 77 78 79 81 82 83
## [76] 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99

Les fonctions définis par l’utilisateur

fun <- function(arguments){expr}

En général, une fonction retourne un résultat qui est la dernière ligne de code du corps de la fonction. Si le résultat n’est pas la dernière ligne alors on peut utiliser l’instruction return(). Lorsqu’une fonction a plusieurs résultats, elle doit retourner une liste nommée.

Toute variable définie dans le corps d’une fonction est dite locale à cette fonction. Nous allons écrire une fonction permettant de simuler des montants agrégés de sinitres. Sur une période d’exercice donnée, par exemple un an, le montant total des sinistres associés à un portefeuille de contrats d’assurance non vie est donnée par

\[ X = \sum_{k=1}^{N}U_k, \]

Cette fonction doit renvoyer l’échantillon ainsi que la proportion de montant agrégé nuls.

Quels sont les paramètres d’une telle fonction?

La première étape est de trouver un nom pour la fonction, qui est souvent un verbe à la forme active, par exemple simulate_X. Une fois les paramètres ajoutés, la documentation de la fonction est générée via Ctrl + Alt + Shift + R ou Code > Insert Roxygen Skeleton.

Une bonne pratique est d’assigner des valeurs par défaut aux paramètres.

#' simulate_X: Simule un échantillon de montants agrégé de sinitre
#'
#' @param loi_N : Loi du nombre de sinistres c('binom', 'nbinom', 'pois')
#' @param loi_U : Loi des montant de sinistre c('gamma', 'lnorm')
#' @param params_loi : c(c(size_N, 0), c(prob_N, lam), c(shape_U, meanlog_U), c(scale_U, sdlog_U))
#' @param sample_size : Taille de l'échantillon
#'
#' @return Un échantillon de montant agrégé de sinistres
#' @export
#'
#' @examples
#
# Le nom de la fonction est généralement un verbe en forme active
# Une fois les paramètres choisis, on génère la documentation
# On peut initialiser les paramètres avec des valeurs par défaut
# Par exemple par défaut on génère des réalisation de loi Poisson-exponentielle
simulate_X <- function(loi_N = 'pois', loi_U = 'gamma', params_loi, sample_size = 1){
  # Simulation des nombres de sinistre nn fonction de la loi choisi
  if( loi_N == 'pois'){# Loi de Poisson
    
    N_vec <- rpois(n = sample_size, lambda = params_loi[2]) 
    
  }else if(loi_N == 'binom'){# Loi binomiale
    
    N_vec <- rbinom(n = sample_size, size = params_loi[1], prob= params_loi[2])
    
  }else{# Loi négative binomiale
    
    N_vec <- rnbinom(n = sample_size, size = params_loi[1], size = params_loi[2])
    }
  # Somme des montants de sinistres pour chaque réalisation du nombre de sinistre en fonction de la loi des montants
  if(loi_U == "gamma"){
    
    X_vec <- unlist(lapply(N_vec, function(N) sum(rgamma(N, shape = params_loi[3], scale = params_loi[4]))))
    
  }else if(loi_U == "lnorm"){
    
    X_vec <- unlist(lapply(N_vec, function(N) sum(rlnorm(N, meanlog = params_loi[3], sdlog = params_loi[4]))))
    
  }
  
res <- list(X_vec, mean(X_vec == 0))
names(res) <- c('echantillon', 'prob0')

return(res)
}
# Test de la fonction
simulate_X(loi_N = 'binom', loi_U = 'lnorm', params_loi = c(10, 1/2, 0, 1), sample_size = 20)
## $echantillon
##  [1]  8.435886  9.605699  7.335410 11.441522  1.992823  5.537488  3.746804
##  [8]  7.480910 11.605210  2.050308 22.250691  1.756884 20.398989  2.593559
## [15]  8.475288 13.377413  3.969116 18.692754  1.258620  7.699364
## 
## $prob0
## [1] 0

Element de deboguage

Il existe plusieurs outils pour régler un problème technique dans une fonction qu’il s’agisse d’un résultat inattendu ou d’une erreur de syntaxe. Il est question dans cette section de la fonction browser, d’autres outils de deboguage existe, voir par exemple cette video. La fonction suivante a pour but l’approximation par simulation de la fonction de répartition de la variable aléatoire \(X\) définit précédemment.

#' approximate_fdr_X approche numériquement la fonction de répartition de X via Monte Carlo
#'
#' @param x : Evaluation de la FDR en x
#' @param loi_N : Loi du nombre de sinistres c('binom', 'nbinom', 'pois')
#' @param loi_U : Loi des montant de sinistre c('gamma', 'lnorm')
#' @param params_loi : c(c(size_N, 0), c(prob_N, lam), c(shape_U, meanlog_U), c(scale_U, sdlog_U))
#' @param sample_size : Taille de l'échantillon
#'
#' @return La valeur de la fonction de répartition de X en x
#' @export
#'
#' @examples
approximate_fdr_X <- function(x = 0, loi_N = 'pois', loi_U = 'gamma', params_loi = c(0, 1, 1, 1), sample_size = 1){
  browser()
  sample_X <- simulate_X(loi_N, loi_U, params_loi, sample_size)$echantillon
  sum(sample_X <= x) / length(sample_X)
}

# approximate_fdr_X(0,'nbinom','gamma', c(5, 1/5, 1, 1), 100)

Il y a bien une erreur dans la fonction simulate_X.

Références