knitr::opts_chunk$set(echo = TRUE,
                      comment = "#>")
library(data.table)

Numeric vs Integer

R écrit par défaut une valeur numeric. Pour obtenir un integer, on doit inscrire L après le nombre.

x <- 100
str(x)
y <- 100L
str(y)

Un des avantages à utiliser les nombres entiers, c'est qu'ils utilisent moins de mémoire que les valeurs numériques. Très utile lorsqu'on travaille avec des bases de données de plusieurs millions d'observations. Prenons par exemple deux fois le même vecteur contenant 10000 valeurs aléatoires entre 1 et 1 million. Le premier est de type numeric et l'autre de type integer.

vec1 <- sample(as.numeric(1:1e6), 10000, TRUE)
object.size(vec1)
vec2 <- as.integer(vec1)
object.size(vec2)

C'est pourquoi, lorsque c'est possible, je priorise integer à numeric.

Never grow a vector

L'une des principales règle en R pour écrire du code efficace, c'est de ne jamais augmenter la taille d'un vecteur.

# Exemple de 'grow a vector' - MAUVAISE UTILISATION
system.time({
  vec <- c()  # créer le vecteur une première fois
  for(i in 1:1e5) vec <- c(vec, i)  # créer un nouveau vecteur à chaque itération
})

# Exemple efficace - Bonne utilisation
system.time({
  vec <- vector("integer", 1e5)  # créer un vecteur une seule fois
  for(i in 1:1e5) vec[i] <- i  # insérer les valeurs dans le vecteur
})

Certains utilisateurs de R priorise la fonction lapply, car elle serait plus rapide que les for loop. La vraie raison est qu'on ne sait pas comment utiliser les for loop à leur plein potentiel.

system.time(lapply(1:1e7, function(i) 2*i - 7))

system.time({
  ll <- vector("list", 1e7)
  for(i in 1:1e7) ll[[i]] <- 2*i - 7
})

Ainsi, créer une liste et modifier les valeurs avec une for loop est plus rapide que d'utiliser la fonction lapply.

Principe de base d'une fonction R

Dans la fonction x_minus_y(x, y, z = NULL), x et y sont des arguments obligatoires, car ils n'ont pas de valeurs par défaut. L'argument z est optionnel, car sa valeur par défaut est NULL. Cela implique que si on n'inscrit pas de troisième argument x_minus_y(x=10, y=3), la fonction utilisera z=NULL et on aura le même résultat que si on avait exécuter le code x_minus_y(x=10, y=3, z=NULL).
Si les arguments ne sont pas nommé, la fonction associe chave valeur dans l'ordre des arguments de la fonction. Par exemple, x_minus_y(x=10, y=2, z=4), x_minus_y(10, 2, 4) et x_minus_y(y=2, z=4, x=10) donneront tous le même résultat. La fonction return(), utilisée dans une autre fonction, permet de retourner un résultat sans exécuter le code qui suit. En d'autres mots, c'est un stop à la fonction. Il n'est pas nécessaire d'utiliser return() dans une fonction, par défaut une fonction R aura pour résultat la dernière ligne de code de la fonction. Ce qui est certain, c'est que d'utiliser return() permet de faciliter la lecture du code, car on sait que la fonction se terminera à ce moment-là.

# Sans utiliser return()
x_minus_y <- function(x, y, z = NULL){
  n <- x - y
  if(!is.null(z)){
     n <- n + z
  }
  n
}

# En utilisant return
x_minus_y_r <- function(x, y, z = NULL){
  if(is.null(z)){
    return(x - y)
  } else {
    return(x - y + z)
  }

  # Écrit sur une seule ligne :
  if(is.null(z)) return(x - y) else return(x - y + z)
}


guiboucher/INESSS-inesss documentation built on April 20, 2020, 10:47 p.m.